diff --git a/CHANGELOG.md b/CHANGELOG.md index 082ee0c1..e905725e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +# v2.6.1-beta + - [#168](https://github.com/xmrig/xmrig-proxy/issues/168) Added support for [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/blob/dev/doc/STRATUM_EXT.md#1-mining-algorithm-negotiation). + - Added IPBC coin support, base algorithm `cn-lite` variant `ipbc`. + - [#581](https://github.com/xmrig/xmrig/issues/581) Added support for upcoming Stellite (XTL) fork, base algorithm `cn` variant `xtl`, variant can set now, no need do it after fork. + - Added support for **rig-id** stratum protocol extensions, compatible with xmr-stak. + - Changed behavior for option `variant=-1` for `cryptonight`, now variant is `1` by default, if you mine old coins need change `variant` to `0`. + - A lot of small fixes and better unification with proxy code. + +# v2.6.0-beta3 +- [#563](https://github.com/xmrig/xmrig/issues/563) **Added [advanced threads mode](https://github.com/xmrig/xmrig/issues/563), now possible configure each thread individually.** +- [#255](https://github.com/xmrig/xmrig/issues/563) Low power mode extended to **triple**, **quard** and **penta** modes. +- [#519](https://github.com/xmrig/xmrig/issues/519) Fixed high donation levels, improved donation start time randomization. +- [#554](https://github.com/xmrig/xmrig/issues/554) Fixed regression with `print-time` option. + +# v2.6.0-beta2 +- Improved performance for `cryptonight v7` especially in double hash mode. +- [#499](https://github.com/xmrig/xmrig/issues/499) IPv6 disabled for internal HTTP API by default, was causing issues on some systems. +- Added short aliases for algorithm names: `cn`, `cn-lite` and `cn-heavy`. +- Fixed regressions (v2.6.0-beta1 affected) + - [#494](https://github.com/xmrig/xmrig/issues/494) Command line option `--donate-level` was broken. + - [#502](https://github.com/xmrig/xmrig/issues/502) Build without libmicrohttpd was broken. + - Fixed nonce calculation for `--av 4` (software AES, double hash) was causing reduction of effective hashrate and rejected shares on nicehash. + +# v2.6.0-beta1 + - [#476](https://github.com/xmrig/xmrig/issues/476) **Added Cryptonight-Heavy support for Sumokoin ASIC resistance fork.** + - HTTP server now runs in main loop, it make possible easy extend API without worry about thread synchronization. + - Added initial graceful reload support, miner will reload configuration if config file changed, disabled by default until it will be fully implemented and tested. + - Added API endpoint `PUT /1/config` to update current config. + - Added API endpoint `GET /1/config` to get current active config. + - Added API endpoint `GET /1/threads` to get current active threads configuration. + - API endpoint `GET /` now deprecated, use `GET /1/summary` instead. + - Added `--api-no-ipv6` and similar config option to disable IPv6 support for HTTP API. + - Added `--api-no-restricted` to enable full access to api, this option has no effect if `--api-access-token` not specified. + # v2.5.3 - Fixed critical bug, in some cases miner was can't recovery connection and switch to failover pool, version 2.5.2 affected. If you use v2.6.0-beta3 this issue doesn't concern you. - [#499](https://github.com/xmrig/xmrig/issues/499) IPv6 support disabled for internal HTTP API. diff --git a/CMakeLists.txt b/CMakeLists.txt index 8823b078..b26b1d93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ project(xmrig) option(WITH_LIBCPUID "Use Libcpuid" ON) option(WITH_AEON "CryptoNight-Lite support" ON) +option(WITH_SUMO "CryptoNight-Heavy support" ON) +option(WITH_IPBC "CryptoNight-IPBC support" ON) option(WITH_HTTPD "HTTP REST API" ON) option(BUILD_STATIC "Build static binary" OFF) @@ -11,53 +13,66 @@ 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/common/config/CommonConfig.h + src/common/config/ConfigLoader.h + src/common/config/ConfigWatcher.h + src/common/Console.h + src/common/crypto/Algorithm.h + src/common/crypto/keccak.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/xmrig.h + src/core/Config.cpp + src/core/ConfigLoader_platform.h + src/core/Controller.h src/Cpu.h src/interfaces/IClientListener.h + src/interfaces/IConfig.h + src/interfaces/IConfigCreator.h src/interfaces/IConsoleListener.h + src/interfaces/IControllerListener.h src/interfaces/IJobResultListener.h src/interfaces/ILogBackend.h src/interfaces/IStrategy.h src/interfaces/IStrategyListener.h + src/interfaces/IThread.h + src/interfaces/IWatcherListener.h src/interfaces/IWorker.h - src/log/ConsoleLog.h - src/log/FileLog.h - src/log/Log.h src/Mem.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/Options.h - src/Platform.h src/Summary.h src/version.h - src/workers/DoubleWorker.h + src/workers/CpuThread.h src/workers/Handle.h src/workers/Hashrate.h - src/workers/SingleWorker.h + src/workers/MultiWorker.h src/workers/Worker.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/groestl_tables.h @@ -73,51 +88,53 @@ else() endif() set(SOURCES - src/api/Api.cpp - src/api/ApiState.cpp src/api/NetworkState.cpp src/App.cpp - src/Console.cpp - src/log/ConsoleLog.cpp - src/log/FileLog.cpp - src/log/Log.cpp + src/common/config/CommonConfig.cpp + src/common/config/ConfigLoader.cpp + src/common/config/ConfigWatcher.cpp + src/common/Console.cpp + src/common/crypto/Algorithm.cpp + src/common/crypto/keccak.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/Mem.cpp - src/net/Client.cpp - src/net/Job.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/Options.cpp - src/Platform.cpp src/Summary.cpp - src/workers/DoubleWorker.cpp + src/workers/CpuThread.cpp src/workers/Handle.cpp src/workers/Hashrate.cpp - src/workers/SingleWorker.cpp + src/workers/MultiWorker.cpp src/workers/Worker.cpp src/workers/Workers.cpp src/xmrig.cpp ) set(SOURCES_CRYPTO - src/crypto/c_keccak.c src/crypto/c_groestl.c src/crypto/c_blake256.c src/crypto/c_jh.c src/crypto/c_skein.c - src/crypto/CryptoNight.cpp ) if (WIN32) set(SOURCES_OS res/app.rc src/App_win.cpp + src/common/Platform_win.cpp src/Cpu_win.cpp src/Mem_win.cpp - src/Platform_win.cpp ) add_definitions(/DWIN32) @@ -125,16 +142,16 @@ if (WIN32) elseif (APPLE) set(SOURCES_OS src/App_unix.cpp + src/common/Platform_mac.cpp src/Cpu_mac.cpp src/Mem_unix.cpp - src/Platform_mac.cpp ) else() set(SOURCES_OS src/App_unix.cpp + src/common/Platform_unix.cpp src/Cpu_unix.cpp src/Mem_unix.cpp - src/Platform_unix.cpp ) set(EXTRA_LIBS pthread rt) @@ -180,19 +197,38 @@ endif() 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 (NOT WITH_AEON) add_definitions(/DXMRIG_NO_AEON) endif() +if (NOT WITH_SUMO) + add_definitions(/DXMRIG_NO_SUMO) +endif() + +if (NOT WITH_IPBC) + add_definitions(/DXMRIG_NO_IPBC) +endif() + if (WITH_HTTPD) find_package(MHD) 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() diff --git a/README.md b/README.md index f69aa346..3d438c5a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # XMRig -:warning: **If you mine Monero, Aeon, Sumokoin, Turtlecoin, Stellite, GRAFT, Haven Protocol, IPBC, [PLEASE READ](https://github.com/xmrig/xmrig/issues/482)!** :warning: +: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).** [![Github All Releases](https://img.shields.io/github/downloads/xmrig/xmrig/total.svg)](https://github.com/xmrig/xmrig/releases) [![GitHub release](https://img.shields.io/github/release/xmrig/xmrig/all.svg)](https://github.com/xmrig/xmrig/releases) @@ -124,10 +124,10 @@ Please note performance is highly dependent on system load. The numbers above ar ## Release checksums ### SHA-256 ``` -5ae25d05b7735dd6e2482e8dba0cf0f5d10f9738855c4ad4eaf449b8ccd2e5be xmrig-2.5.3-xenial-amd64.tar.gz/xmrig-2.5.3/xmrig -f11f3b381425ca4181c425d5b693407431f964759bb903f66b7cd2345fcdd786 xmrig-2.5.3-gcc-win32.zip/xmrig.exe -67df8b89714e2921931092861361dbae4716c4ab872c767c92adae24dca01514 xmrig-2.5.3-gcc-win64.zip/xmrig.exe -52bf6e0ef72c84282f4df411125384444c521ed9143e5d8c7e7e445d7d55e143 xmrig-2.5.3-msvc-win64.zip/xmrig.exe +6b32fefb356b27caa2180be17755d09639f0654096a1a0c61e8f10f4f2ac1626 xmrig-2.6.0-beta3-xenial-amd64.tar.gz/xmrig-2.6.0-beta3/xmrig +c8b40f4d7aac9d0cc7c3d02cadeac91b0bdb034aae2fb6b415d503272eabb987 xmrig-2.6.0-beta3-gcc-win32.zip/xmrig.exe +32cf7958f97a23296186e38a4addb9cf234adcbd9c7914b15e4209a87fe272e7 xmrig-2.6.0-beta3-gcc-win64.zip/xmrig.exe +4f176ee4c4be52701edc0d573cf9647c4aacbb4ff14975b80b98e6fe63068542 xmrig-2.6.0-beta3-msvc-win64.zip/xmrig.exe ``` ## Contacts diff --git a/cmake/flags.cmake b/cmake/flags.cmake index 13e50564..498f2165 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -13,10 +13,10 @@ endif() if (CMAKE_CXX_COMPILER_ID MATCHES GNU) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-strict-aliasing") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-exceptions -fno-rtti") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -s -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -s") if (XMRIG_ARMv8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a+crypto") diff --git a/doc/ALGORITHMS.md b/doc/ALGORITHMS.md new file mode 100644 index 00000000..d9a34a16 --- /dev/null +++ b/doc/ALGORITHMS.md @@ -0,0 +1,44 @@ +# Algorithms + +XMRig uses a different way to specify algorithms, compared to other miners. + +Algorithm selection splitted to 2 parts: + + * Global base algorithm per miner or proxy instance, `algo` option. Possible values: `cryptonight`, `cryptonight-lite`, `cryptonight-heavy`. + * Algorithm variant specified separately for each pool, `variant` option. + +Possible variants for `cryptonight`: + + * `0` Original cryptonight. + * `1` cryptonight variant 1, also known as cryptonight v7 or monero7. + * `"xtl"` Stellite coin variant. + +Possible variants for `cryptonight-lite`: + + * `0` Original cryptonight-lite. + * `1` cryptonight-lite variant 1, also known as cryptonight-lite v7 or aeon7. + * `"ipbc"` IPBC coin variant. + +For `cryptonight-heavy` currently no variants. + + +### Cheatsheet + +You mine **Sumokoin** or **Haven Protocol**? +Your algorithm is `cryptonight-heavy` no variant option need. + +You mine **Aeon**, **TurtleCoin** or **IPBC**? +Your base algorithm is `cryptonight-lite`: + +Variants: + * Aeon: `-1` autodetect. `0` right now, `1` after fork. + * TurtleCoin: `1`. + * IPBC: `"ipbc"`. + +In all other cases base algorithm is `cryptonight`. + +### Mining algorithm negotiation +If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) miner will choice proper variant automaticaly and if you choice wrong base algorithm you will see error message. + +Pools with mining algorithm negotiation support. + * [www.hashvault.pro](https://www.hashvault.pro/) diff --git a/doc/API.md b/doc/API.md new file mode 100644 index 00000000..3357eabb --- /dev/null +++ b/doc/API.md @@ -0,0 +1,53 @@ +# HTTP API + +If you want use API you need choice a port where is internal HTTP server will listen for incoming connections. API will not available if miner built without `libmicrohttpd`. + +Example configuration: + +```json +"api": { + "port": 44444, + "access-token": "TOKEN", + "worker-id": null, + "ipv6": false, + "restricted": false +}, +``` + +* **port** Port for incoming connections `http://:`. +* **access-token** [Bearer](https://gist.github.com/xmrig/c75fdd1f8e0f3bac05500be2ab718f8e#file-api-html-L54) access token to secure access to API. +* **worker-id** Optional worker name, if not set will be detected automatically. +* **ipv6** Enable (`true`) or disable (`false`) IPv6 for API. +* **restricted** Use `false` to allow remote configuration. + +If you prefer use command line options instead of config file, you can use options: `--api-port`, `--api-access-token`, `--api-worker-id`, `--api-ipv6` and `api-no-restricted`. + +## Endpoints + +### GET /1/summary + +Get miner summary information. [Example](api/1/summary.json). + +### GET /1/threads + +Get detailed information about miner threads. [Example](api/1/threads.json). + + +## Restricted endpoints + +All API endpoints below allow access to sensitive information and remote configure miner. You should set `access-token` and allow unrestricted access (`"restricted": false`). + +### GET /1/config + +Get current miner configuration. [Example](api/1/config.json). + + +### PUT /1/config + +Update current miner configuration. Common use case, get current configuration, make changes, and upload it to miner. + +Curl example: + +``` +curl -v --data-binary @config.json -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer SECRET" http://127.0.0.1:44444/1/config +``` \ No newline at end of file diff --git a/doc/api/1/config.json b/doc/api/1/config.json new file mode 100644 index 00000000..2c74cfba --- /dev/null +++ b/doc/api/1/config.json @@ -0,0 +1,63 @@ +{ + "algo": "cryptonight", + "api": { + "port": 44444, + "access-token": "TOKEN", + "worker-id": null, + "ipv6": false, + "restricted": false + }, + "av": 1, + "background": false, + "colors": true, + "cpu-affinity": null, + "cpu-priority": null, + "donate-level": 5, + "huge-pages": true, + "hw-aes": null, + "log-file": null, + "max-cpu-usage": 75, + "pools": [ + { + "url": "pool.monero.hashvault.pro:3333", + "user": "48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD", + "pass": "x", + "keepalive": false, + "nicehash": false, + "variant": -1 + }, + { + "url": "pool.supportxmr.com:3333", + "user": "48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD", + "pass": "x", + "keepalive": false, + "nicehash": false, + "variant": -1 + } + ], + "print-time": 60, + "retries": 5, + "retry-pause": 5, + "safe": false, + "threads": [ + { + "low_power_mode": 1, + "affine_to_cpu": 0 + }, + { + "low_power_mode": 1, + "affine_to_cpu": 1 + }, + { + "low_power_mode": 1, + "affine_to_cpu": 2 + }, + { + "low_power_mode": 1, + "affine_to_cpu": 3 + } + ], + "user-agent": null, + "syslog": false, + "watch": false +} \ No newline at end of file diff --git a/doc/api/1/summary.json b/doc/api/1/summary.json new file mode 100644 index 00000000..ed3cd128 --- /dev/null +++ b/doc/api/1/summary.json @@ -0,0 +1,73 @@ +{ + "id": "92f3104f9a2ee78c", + "worker_id": "Ubuntu-1604-xenial-64-minimal", + "version": "2.6.0-beta3", + "kind": "cpu", + "ua": "XMRig/2.6.0-beta3 (Linux x86_64) libuv/1.8.0 gcc/5.4.0", + "cpu": { + "brand": "Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz", + "aes": true, + "x64": true, + "sockets": 1 + }, + "algo": "cryptonight", + "hugepages": true, + "donate_level": 5, + "hashrate": { + "total": [ + 296.24, + 296.23, + 295.97 + ], + "highest": 296.5, + "threads": [ + [ + 73.39, + 73.39, + 73.28 + ], + [ + 74.72, + 74.72, + 74.71 + ], + [ + 74.72, + 74.72, + 74.71 + ], + [ + 73.39, + 73.39, + 73.27 + ] + ] + }, + "results": { + "diff_current": 9990, + "shares_good": 30, + "shares_total": 30, + "avg_time": 31, + "hashes_total": 311833, + "best": [ + 278199, + 181923, + 103717, + 96632, + 56154, + 51580, + 45667, + 33159, + 29581, + 29514 + ], + "error_log": [] + }, + "connection": { + "pool": "pool.monero.hashvault.pro:3333", + "uptime": 953, + "ping": 35, + "failures": 0, + "error_log": [] + } +} \ No newline at end of file diff --git a/doc/api/1/threads.json b/doc/api/1/threads.json new file mode 100644 index 00000000..e536883d --- /dev/null +++ b/doc/api/1/threads.json @@ -0,0 +1,65 @@ +{ + "hugepages": [ + 4, + 4 + ], + "memory": 8388608, + "threads": [ + { + "type": "cpu", + "algo": "cryptonight", + "av": 1, + "low_power_mode": 1, + "affine_to_cpu": 0, + "priority": -1, + "soft_aes": false, + "hashrate": [ + 73.39, + 73.4, + 73.28 + ] + }, + { + "type": "cpu", + "algo": "cryptonight", + "av": 1, + "low_power_mode": 1, + "affine_to_cpu": 1, + "priority": -1, + "soft_aes": false, + "hashrate": [ + 74.72, + 74.72, + 74.7 + ] + }, + { + "type": "cpu", + "algo": "cryptonight", + "av": 1, + "low_power_mode": 1, + "affine_to_cpu": 2, + "priority": -1, + "soft_aes": false, + "hashrate": [ + 74.71, + 74.72, + 74.7 + ] + }, + { + "type": "cpu", + "algo": "cryptonight", + "av": 1, + "low_power_mode": 1, + "affine_to_cpu": 3, + "priority": -1, + "soft_aes": false, + "hashrate": [ + 73.39, + 73.4, + 73.28 + ] + } + ] +} \ No newline at end of file diff --git a/res/app.rc b/res/app.rc index 800ce2dd..037d842a 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/App.cpp b/src/App.cpp index d656acc8..adcc5752 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-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 @@ -28,27 +28,22 @@ #include "api/Api.h" #include "App.h" -#include "Console.h" +#include "common/Console.h" +#include "common/log/Log.h" +#include "common/Platform.h" +#include "core/Config.h" +#include "core/Controller.h" #include "Cpu.h" #include "crypto/CryptoNight.h" -#include "log/ConsoleLog.h" -#include "log/FileLog.h" -#include "log/Log.h" #include "Mem.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 @@ -58,40 +53,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()); - Platform::setProcessPriority(m_options->priority()); - - 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); @@ -102,17 +76,18 @@ 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) { + if (!m_controller->isReady()) { return 2; } @@ -122,15 +97,11 @@ int App::exec() background(); - if (!CryptoNight::init(m_options->algo(), m_options->algoVariant())) { - LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName()); - return 1; - } + Mem::init(m_controller->config()->isHugePages()); - Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash(), m_options->hugePages()); - Summary::print(); + Summary::print(m_controller); - if (m_options->dryRun()) { + if (m_controller->config()->isDryRun()) { LOG_NOTICE("OK"); release(); @@ -138,17 +109,23 @@ int App::exec() } # 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->affinity(), m_options->priority()); + Workers::start(m_controller); - m_network->connect(); + m_controller->network()->connect(); const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); uv_loop_close(uv_default_loop()); @@ -169,7 +146,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; @@ -177,7 +154,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; @@ -195,7 +172,7 @@ void App::onConsoleCommand(char command) void App::close() { - m_network->stop(); + m_controller->network()->stop(); Workers::stop(); uv_stop(uv_default_loop()); @@ -204,13 +181,6 @@ void App::close() void App::release() { - if (m_network) { - delete m_network; - } - - Options::release(); - Mem::release(); - Platform::release(); } diff --git a/src/App.h b/src/App.h index 1b96040d..22269f67 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-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 @@ -37,6 +37,11 @@ class Network; class Options; +namespace xmrig { + class Controller; +} + + class App : public IConsoleListener { public: @@ -59,11 +64,10 @@ private: 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 674a53e6..45f73d2d 100644 --- a/src/App_unix.cpp +++ b/src/App_unix.cpp @@ -29,20 +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->affinity() != -1L) { - Cpu::setAffinity(-1, m_options->affinity()); - } - - if (!m_options->background()) { + if (!m_controller->config()->isBackground()) { return; } diff --git a/src/App_win.cpp b/src/App_win.cpp index 895f3bdf..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,17 +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->affinity() != -1L) { - Cpu::setAffinity(-1, m_options->affinity()); - } - - if (!m_options->background()) { + if (!m_controller->config()->isBackground()) { return; } diff --git a/src/Cpu.cpp b/src/Cpu.cpp index eba993b3..eebe585d 100644 --- a/src/Cpu.cpp +++ b/src/Cpu.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 @@ -26,26 +26,27 @@ #include #include + #include "Cpu.h" -bool Cpu::m_l2_exclusive = false; -char Cpu::m_brand[64] = { 0 }; -int Cpu::m_flags = 0; -int Cpu::m_l2_cache = 0; -int Cpu::m_l3_cache = 0; -int Cpu::m_sockets = 1; -int Cpu::m_totalCores = 0; -int Cpu::m_totalThreads = 0; +bool Cpu::m_l2_exclusive = false; +char Cpu::m_brand[64] = { 0 }; +int Cpu::m_flags = 0; +int Cpu::m_l2_cache = 0; +int Cpu::m_l3_cache = 0; +int Cpu::m_sockets = 1; +int Cpu::m_totalCores = 0; +size_t Cpu::m_totalThreads = 0; -int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage) +size_t Cpu::optimalThreadsCount(size_t size, int maxCpuUsage) { if (m_totalThreads == 1) { return 1; } - int cache = 0; + size_t cache = 0; if (m_l3_cache) { cache = m_l2_exclusive ? (m_l2_cache + m_l3_cache) : m_l3_cache; } @@ -53,11 +54,14 @@ int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage) cache = m_l2_cache; } - int count = 0; - const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1); + size_t count = 0; if (cache) { count = cache / size; + + if (cache % size >= size / 2) { + count++; + } } else { count = m_totalThreads / 2; diff --git a/src/Cpu.h b/src/Cpu.h index 9444274d..a125bae8 100644 --- a/src/Cpu.h +++ b/src/Cpu.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 @@ -37,9 +37,8 @@ public: BMI2 = 4 }; - static int optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage); + static size_t optimalThreadsCount(size_t size, int maxCpuUsage); static void init(); - static void setAffinity(int id, uint64_t mask); static inline bool hasAES() { return (m_flags & AES) != 0; } static inline bool isX64() { return (m_flags & X86_64) != 0; } @@ -60,7 +59,7 @@ private: static int m_l3_cache; static int m_sockets; static int m_totalCores; - static int m_totalThreads; + static size_t m_totalThreads; }; diff --git a/src/Cpu_arm.cpp b/src/Cpu_arm.cpp index c2047ffb..59ff8421 100644 --- a/src/Cpu_arm.cpp +++ b/src/Cpu_arm.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 @@ -28,16 +28,16 @@ #include "Cpu.h" -char Cpu::m_brand[64] = { 0 }; -int Cpu::m_flags = 0; -int Cpu::m_l2_cache = 0; -int Cpu::m_l3_cache = 0; -int Cpu::m_sockets = 1; -int Cpu::m_totalCores = 0; -int Cpu::m_totalThreads = 0; +char Cpu::m_brand[64] = { 0 }; +int Cpu::m_flags = 0; +int Cpu::m_l2_cache = 0; +int Cpu::m_l3_cache = 0; +int Cpu::m_sockets = 1; +int Cpu::m_totalCores = 0; +size_t Cpu::m_totalThreads = 0; -int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage) +size_t Cpu::optimalThreadsCount(size_t size, int maxCpuUsage) { return m_totalThreads; } diff --git a/src/Cpu_mac.cpp b/src/Cpu_mac.cpp index 357e15ef..085148bc 100644 --- a/src/Cpu_mac.cpp +++ b/src/Cpu_mac.cpp @@ -4,8 +4,8 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2016-2017 XMRig - * + * 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 @@ -38,8 +38,3 @@ void Cpu::init() initCommon(); } - - -void Cpu::setAffinity(int id, uint64_t mask) -{ -} diff --git a/src/Cpu_unix.cpp b/src/Cpu_unix.cpp index 9a13e7a5..b895c897 100644 --- a/src/Cpu_unix.cpp +++ b/src/Cpu_unix.cpp @@ -52,28 +52,3 @@ void Cpu::init() initCommon(); } - - -void Cpu::setAffinity(int id, uint64_t mask) -{ - cpu_set_t set; - CPU_ZERO(&set); - - for (int i = 0; i < m_totalThreads; i++) { - if (mask & (1UL << i)) { - CPU_SET(i, &set); - } - } - - if (id == -1) { -# ifndef __FreeBSD__ - sched_setaffinity(0, sizeof(&set), &set); -# endif - } else { -# ifndef __ANDROID__ - pthread_setaffinity_np(pthread_self(), sizeof(&set), &set); -# else - sched_setaffinity(gettid(), sizeof(&set), &set); -# endif - } -} diff --git a/src/Cpu_win.cpp b/src/Cpu_win.cpp index 13113a17..7258f726 100644 --- a/src/Cpu_win.cpp +++ b/src/Cpu_win.cpp @@ -39,14 +39,3 @@ void Cpu::init() initCommon(); } - - -void Cpu::setAffinity(int id, uint64_t mask) -{ - if (id == -1) { - SetProcessAffinityMask(GetCurrentProcess(), mask); - } - else { - SetThreadAffinityMask(GetCurrentThread(), mask); - } -} diff --git a/src/Mem.cpp b/src/Mem.cpp index b32d2196..bb2da646 100644 --- a/src/Mem.cpp +++ b/src/Mem.cpp @@ -23,68 +23,49 @@ */ -#include - - +#include "common/utils/mm_malloc.h" #include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" #include "Mem.h" -#include "Options.h" -#include "xmrig.h" -bool Mem::m_doubleHash = false; -int Mem::m_algo = 0; -int Mem::m_flags = 0; -int Mem::m_threads = 0; -size_t Mem::m_offset = 0; -size_t Mem::m_size = 0; -alignas(16) uint8_t *Mem::m_memory = nullptr; +bool Mem::m_enabled = true; +int Mem::m_flags = 0; -cryptonight_ctx *Mem::create(int threadId) + +MemInfo Mem::create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count) { + using namespace xmrig; + + MemInfo info; + info.size = cn_select_memory(algorithm) * count; + # ifndef XMRIG_NO_AEON - if (m_algo == xmrig::ALGO_CRYPTONIGHT_LITE) { - return createLite(threadId); - } + info.size += info.size % cn_select_memory(); # endif - cryptonight_ctx *ctx = reinterpret_cast(&m_memory[MONERO_MEMORY - sizeof(cryptonight_ctx) * (threadId + 1)]); + info.pages = info.size / cn_select_memory(); - const int ratio = m_doubleHash ? 2 : 1; - ctx->memory = &m_memory[MONERO_MEMORY * (threadId * ratio + 1)]; + allocate(info, m_enabled); - return ctx; -} + for (size_t i = 0; i < count; ++i) { + cryptonight_ctx *c = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 4096)); + c->memory = info.memory + (i * cn_select_memory(algorithm)); - - -void *Mem::calloc(size_t num, size_t size) -{ - void *mem = &m_memory[m_offset]; - m_offset += (num * size); - - memset(mem, 0, num * size); - - return mem; -} - - -#ifndef XMRIG_NO_AEON -cryptonight_ctx *Mem::createLite(int threadId) { - cryptonight_ctx *ctx; - - if (!m_doubleHash) { - const size_t offset = MONERO_MEMORY * (threadId + 1); - - ctx = reinterpret_cast(&m_memory[offset + AEON_MEMORY]); - ctx->memory = &m_memory[offset]; - return ctx; + ctx[i] = c; } - ctx = reinterpret_cast(&m_memory[MONERO_MEMORY - sizeof(cryptonight_ctx) * (threadId + 1)]); - ctx->memory = &m_memory[MONERO_MEMORY * (threadId + 1)]; - - return ctx; + return info; } -#endif + + +void Mem::release(cryptonight_ctx **ctx, size_t count, MemInfo &info) +{ + release(info); + + for (size_t i = 0; i < count; ++i) { + _mm_free(ctx[i]); + } +} + diff --git a/src/Mem.h b/src/Mem.h index 18914d68..6fd18fc1 100644 --- a/src/Mem.h +++ b/src/Mem.h @@ -30,9 +30,22 @@ #include +#include "common/xmrig.h" + + struct cryptonight_ctx; +struct MemInfo +{ + alignas(16) uint8_t *memory; + + size_t hugePages; + size_t pages; + size_t size; +}; + + class Mem { public: @@ -42,29 +55,18 @@ public: Lock = 4 }; - static bool allocate(int algo, int threads, bool doubleHash, bool enabled); - static cryptonight_ctx *create(int threadId); - static void *calloc(size_t num, size_t size); - static void release(); + static MemInfo create(cryptonight_ctx **ctx, xmrig::Algo algorithm, size_t count); + static void init(bool enabled); + static void release(cryptonight_ctx **ctx, size_t count, MemInfo &info); - static inline bool isDoubleHash() { return m_doubleHash; } static inline bool isHugepagesAvailable() { return (m_flags & HugepagesAvailable) != 0; } - static inline bool isHugepagesEnabled() { return (m_flags & HugepagesEnabled) != 0; } - static inline int flags() { return m_flags; } - static inline int threads() { return m_threads; } private: - static bool m_doubleHash; - static int m_algo; - static int m_flags; - static int m_threads; - static size_t m_offset; - static size_t m_size; - alignas(16) static uint8_t *m_memory; + static void allocate(MemInfo &info, bool enabled); + static void release(MemInfo &info); -# ifndef XMRIG_NO_AEON - static cryptonight_ctx *createLite(int threadId); -# endif + static int m_flags; + static bool m_enabled; }; diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp index 3e699544..c1aa0fb1 100644 --- a/src/Mem_unix.cpp +++ b/src/Mem_unix.cpp @@ -27,72 +27,63 @@ #include -#if defined(XMRIG_ARM) && !defined(__clang__) -# include "aligned_malloc.h" -#else -# include -#endif - - +#include "common/log/Log.h" +#include "common/utils/mm_malloc.h" +#include "common/xmrig.h" #include "crypto/CryptoNight.h" -#include "log/Log.h" #include "Mem.h" -#include "Options.h" -#include "xmrig.h" -bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled) +void Mem::init(bool enabled) { - m_algo = algo; - m_threads = threads; - m_doubleHash = doubleHash; + m_enabled = enabled; +} - const int ratio = (doubleHash && algo != xmrig::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; - m_size = MONERO_MEMORY * (threads * ratio + 1); + +void Mem::allocate(MemInfo &info, bool enabled) +{ + info.hugePages = 0; if (!enabled) { - m_memory = static_cast(_mm_malloc(m_size, 16)); - return true; - } + info.memory = static_cast(_mm_malloc(info.size, 4096)); - m_flags |= HugepagesAvailable; + return; + } # if defined(__APPLE__) - m_memory = static_cast(mmap(0, m_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0)); + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0)); # elif defined(__FreeBSD__) - m_memory = static_cast(mmap(0, m_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0)); + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0)); # else - m_memory = static_cast(mmap(0, m_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0)); + info.memory = static_cast(mmap(0, info.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0)); # endif - if (m_memory == MAP_FAILED) { - m_memory = static_cast(_mm_malloc(m_size, 16)); - return true; + + if (info.memory == MAP_FAILED) { + return allocate(info, false);; } - m_flags |= HugepagesEnabled; + info.hugePages = info.pages; - if (madvise(m_memory, m_size, MADV_RANDOM | MADV_WILLNEED) != 0) { + if (madvise(info.memory, info.size, MADV_RANDOM | MADV_WILLNEED) != 0) { LOG_ERR("madvise failed"); } - if (mlock(m_memory, m_size) == 0) { + if (mlock(info.memory, info.size) == 0) { m_flags |= Lock; } - - return true; } -void Mem::release() +void Mem::release(MemInfo &info) { - if (m_flags & HugepagesEnabled) { + if (info.hugePages) { if (m_flags & Lock) { - munlock(m_memory, m_size); + munlock(info.memory, info.size); } - munmap(m_memory, m_size); + munmap(info.memory, info.size); } else { - _mm_free(m_memory); + _mm_free(info.memory); } } diff --git a/src/Mem_win.cpp b/src/Mem_win.cpp index 239bda7d..2bfcc3b0 100644 --- a/src/Mem_win.cpp +++ b/src/Mem_win.cpp @@ -28,17 +28,13 @@ #include #include -#ifdef __GNUC__ -# include -#else -# include -#endif -#include "log/Log.h" +#include "common/log/Log.h" +#include "common/utils/mm_malloc.h" +#include "common/xmrig.h" #include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" #include "Mem.h" -#include "Options.h" -#include "xmrig.h" /***************************************************************** @@ -146,42 +142,43 @@ static BOOL TrySetLockPagesPrivilege() { } -bool Mem::allocate(int algo, int threads, bool doubleHash, bool enabled) +void Mem::init(bool enabled) { - m_algo = algo; - m_threads = threads; - m_doubleHash = doubleHash; + m_enabled = enabled; - const int ratio = (doubleHash && algo != xmrig::ALGO_CRYPTONIGHT_LITE) ? 2 : 1; - m_size = MONERO_MEMORY * (threads * ratio + 1); - - if (!enabled) { - m_memory = static_cast(_mm_malloc(m_size, 16)); - return true; - } - - if (TrySetLockPagesPrivilege()) { + if (enabled && TrySetLockPagesPrivilege()) { m_flags |= HugepagesAvailable; } - - m_memory = static_cast(VirtualAlloc(NULL, m_size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE)); - if (!m_memory) { - m_memory = static_cast(_mm_malloc(m_size, 16)); - } - else { - m_flags |= HugepagesEnabled; - } - - return true; } -void Mem::release() +void Mem::allocate(MemInfo &info, bool enabled) { - if (m_flags & HugepagesEnabled) { - VirtualFree(m_memory, 0, MEM_RELEASE); + info.hugePages = 0; + + if (!enabled) { + info.memory = static_cast(_mm_malloc(info.size, 4096)); + + return; + } + + info.memory = static_cast(VirtualAlloc(nullptr, info.size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE)); + if (info.memory) { + info.hugePages = info.pages; + + return; + } + + allocate(info, false); +} + + +void Mem::release(MemInfo &info) +{ + if (info.hugePages) { + VirtualFree(info.memory, 0, MEM_RELEASE); } else { - _mm_free(m_memory); + _mm_free(info.memory); } } diff --git a/src/Options.cpp b/src/Options.cpp deleted file mode 100644 index 939075f8..00000000 --- a/src/Options.cpp +++ /dev/null @@ -1,761 +0,0 @@ -/* 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 "getopt/getopt.h" -#else -# include -#endif - - -#ifndef XMRIG_NO_HTTPD -# include -#endif - - -#include "Cpu.h" -#include "donate.h" -#include "net/Url.h" -#include "Options.h" -#include "Platform.h" -#include "rapidjson/document.h" -#include "rapidjson/error/en.h" -#include "rapidjson/filereadstream.h" -#include "version.h" -#include "xmrig.h" - - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif - - -Options *Options::m_self = nullptr; - - -static char const usage[] = "\ -Usage: " APP_ID " [OPTIONS]\n\ -Options:\n\ - -a, --algo=ALGO cryptonight (default) or cryptonight-lite\n\ - -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\ - -t, --threads=N number of miner threads\n\ - -v, --av=N algorithm variation, 0 auto select\n\ - -k, --keepalive send keepalived for prevent timeout (need pool support)\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\ - --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ - --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ - --no-huge-pages disable huge pages support\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 -"\ - --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\ - --safe safe adjust threads and av settings for current CPU\n\ - --nicehash enable nicehash/xmrig-proxy support\n\ - --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\ - -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:T:o:u:O:v:Vl:S"; - - -static struct option const options[] = { - { "algo", 1, nullptr, 'a' }, - { "api-access-token", 1, nullptr, 4001 }, - { "api-port", 1, nullptr, 4000 }, - { "api-worker-id", 1, nullptr, 4002 }, - { "av", 1, nullptr, 'v' }, - { "background", 0, nullptr, 'B' }, - { "config", 1, nullptr, 'c' }, - { "cpu-affinity", 1, nullptr, 1020 }, - { "cpu-priority", 1, nullptr, 1021 }, - { "donate-level", 1, nullptr, 1003 }, - { "dry-run", 0, nullptr, 5000 }, - { "help", 0, nullptr, 'h' }, - { "keepalive", 0, nullptr ,'k' }, - { "log-file", 1, nullptr, 'l' }, - { "max-cpu-usage", 1, nullptr, 1004 }, - { "nicehash", 0, nullptr, 1006 }, - { "no-color", 0, nullptr, 1002 }, - { "no-huge-pages", 0, nullptr, 1009 }, - { "variant", 1, nullptr, 1010 }, - { "pass", 1, nullptr, 'p' }, - { "print-time", 1, nullptr, 1007 }, - { "retries", 1, nullptr, 'r' }, - { "retry-pause", 1, nullptr, 'R' }, - { "safe", 0, nullptr, 1005 }, - { "syslog", 0, nullptr, 'S' }, - { "threads", 1, nullptr, 't' }, - { "url", 1, nullptr, 'o' }, - { "user", 1, nullptr, 'u' }, - { "user-agent", 1, nullptr, 1008 }, - { "userpass", 1, nullptr, 'O' }, - { "version", 0, nullptr, 'V' }, - { 0, 0, 0, 0 } -}; - - -static struct option const config_options[] = { - { "algo", 1, nullptr, 'a' }, - { "av", 1, nullptr, 'v' }, - { "background", 0, nullptr, 'B' }, - { "colors", 0, nullptr, 2000 }, - { "cpu-affinity", 1, nullptr, 1020 }, - { "cpu-priority", 1, nullptr, 1021 }, - { "donate-level", 1, nullptr, 1003 }, - { "dry-run", 0, nullptr, 5000 }, - { "huge-pages", 0, nullptr, 1009 }, - { "log-file", 1, nullptr, 'l' }, - { "max-cpu-usage", 1, nullptr, 1004 }, - { "print-time", 1, nullptr, 1007 }, - { "retries", 1, nullptr, 'r' }, - { "retry-pause", 1, nullptr, 'R' }, - { "safe", 0, nullptr, 1005 }, - { "syslog", 0, nullptr, 'S' }, - { "threads", 1, nullptr, 't' }, - { "user-agent", 1, nullptr, 1008 }, - { 0, 0, 0, 0 } -}; - - -static struct option const pool_options[] = { - { "url", 1, nullptr, 'o' }, - { "pass", 1, nullptr, 'p' }, - { "user", 1, nullptr, 'u' }, - { "userpass", 1, nullptr, 'O' }, - { "keepalive", 0, nullptr ,'k' }, - { "variant", 1, nullptr, 1010 }, - { "nicehash", 0, nullptr, 1006 }, - { 0, 0, 0, 0 } -}; - - -static struct option const api_options[] = { - { "port", 1, nullptr, 4000 }, - { "access-token", 1, nullptr, 4001 }, - { "worker-id", 1, nullptr, 4002 }, - { 0, 0, 0, 0 } -}; - - -static const char *algo_names[] = { - "cryptonight", -# ifndef XMRIG_NO_AEON - "cryptonight-lite" -# endif -}; - - -Options *Options::parse(int argc, char **argv) -{ - Options *options = new Options(argc, argv); - if (options->isReady()) { - m_self = options; - return m_self; - } - - delete options; - return nullptr; -} - - -const char *Options::algoName() const -{ - return algo_names[m_algo]; -} - - -Options::Options(int argc, char **argv) : - m_background(false), - m_colors(true), - m_doubleHash(false), - m_dryRun(false), - m_hugePages(true), - m_ready(false), - m_safe(false), - m_syslog(false), - m_apiToken(nullptr), - m_apiWorkerId(nullptr), - m_logFile(nullptr), - m_userAgent(nullptr), - m_algo(0), - m_algoVariant(0), - m_apiPort(0), - m_donateLevel(kDonateLevel), - m_maxCpuUsage(75), - m_printTime(60), - m_priority(-1), - m_retries(5), - m_retryPause(5), - m_threads(0), - m_affinity(-1L) -{ - m_pools.push_back(new Url()); - - int key; - - while (1) { - key = getopt_long(argc, argv, short_options, options, NULL); - if (key < 0) { - break; - } - - if (!parseArg(key, optarg)) { - return; - } - } - - if (optind < argc) { - fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], argv[optind]); - return; - } - - if (!m_pools[0]->isValid()) { - parseConfig(Platform::defaultConfigName()); - } - - if (!m_pools[0]->isValid()) { - fprintf(stderr, "No pool URL supplied. Exiting.\n"); - return; - } - - m_algoVariant = getAlgoVariant(); - if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) { - m_doubleHash = true; - } - - if (!m_threads) { - m_threads = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage); - } - else if (m_safe) { - const int count = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage); - if (m_threads > count) { - m_threads = count; - } - } - - adjust(); - - m_ready = true; -} - - -Options::~Options() -{ -} - - -bool Options::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 Options::parseArg(int key, const char *arg) -{ - switch (key) { - case 'a': /* --algo */ - if (!setAlgo(arg)) { - return false; - } - break; - - case 'o': /* --url */ - if (m_pools.size() > 1 || m_pools[0]->isValid()) { - Url *url = new Url(arg); - if (url->isValid()) { - m_pools.push_back(url); - } - else { - delete url; - } - } - else { - m_pools[0]->parse(arg); - } - - if (!m_pools.back()->isValid()) { - return false; - } - break; - - case 'O': /* --userpass */ - if (!m_pools.back()->setUserpass(arg)) { - return false; - } - break; - - case 'u': /* --user */ - m_pools.back()->setUser(arg); - break; - - case 'p': /* --pass */ - m_pools.back()->setPassword(arg); - break; - - case 'l': /* --log-file */ - free(m_logFile); - m_logFile = strdup(arg); - m_colors = false; - break; - - case 4001: /* --access-token */ - free(m_apiToken); - m_apiToken = strdup(arg); - break; - - case 4002: /* --worker-id */ - free(m_apiWorkerId); - m_apiWorkerId = strdup(arg); - break; - - case 'r': /* --retries */ - case 'R': /* --retry-pause */ - case 'v': /* --av */ - case 1003: /* --donate-level */ - case 1004: /* --max-cpu-usage */ - case 1007: /* --print-time */ - case 1021: /* --cpu-priority */ - case 4000: /* --api-port */ - case 1010: /* --variant */ - return parseArg(key, strtol(arg, nullptr, 10)); - - case 'B': /* --background */ - case 'k': /* --keepalive */ - case 'S': /* --syslog */ - case 1005: /* --safe */ - case 1006: /* --nicehash */ - case 5000: /* --dry-run */ - return parseBoolean(key, true); - - case 1002: /* --no-color */ - case 1009: /* --no-huge-pages */ - return parseBoolean(key, false); - - case 't': /* --threads */ - if (strncmp(arg, "all", 3) == 0) { - m_threads = Cpu::threads(); - return true; - } - - return parseArg(key, strtol(arg, nullptr, 10)); - - case 'V': /* --version */ - showVersion(); - return false; - - case 'h': /* --help */ - showUsage(0); - return false; - - case 'c': /* --config */ - parseConfig(arg); - break; - - case 1020: { /* --cpu-affinity */ - const char *p = strstr(arg, "0x"); - return parseArg(key, p ? strtoull(p, nullptr, 16) : strtoull(arg, nullptr, 10)); - } - - case 1008: /* --user-agent */ - free(m_userAgent); - m_userAgent = strdup(arg); - break; - - default: - showUsage(1); - return false; - } - - return true; -} - - -bool Options::parseArg(int key, uint64_t arg) -{ - switch (key) { - case 'r': /* --retries */ - if (arg < 1 || arg > 1000) { - showUsage(1); - return false; - } - - m_retries = (int) arg; - break; - - case 'R': /* --retry-pause */ - if (arg < 1 || arg > 3600) { - showUsage(1); - return false; - } - - m_retryPause = (int) arg; - break; - - case 't': /* --threads */ - if (arg < 1 || arg > 1024) { - showUsage(1); - return false; - } - - m_threads = (int) arg; - break; - - case 'v': /* --av */ - if (arg > 1000) { - showUsage(1); - return false; - } - - m_algoVariant = (int) arg; - break; - - case 1003: /* --donate-level */ - if (arg < 1 || arg > 99) { - return true; - } - - m_donateLevel = (int) arg; - break; - - case 1004: /* --max-cpu-usage */ - if (arg < 1 || arg > 100) { - showUsage(1); - return false; - } - - m_maxCpuUsage = (int) arg; - break; - - case 1007: /* --print-time */ - if (arg > 1000) { - showUsage(1); - return false; - } - - m_printTime = (int) arg; - break; - - case 1010: /* --variant */ - m_pools.back()->setVariant((int) arg); - break; - - case 1020: /* --cpu-affinity */ - if (arg) { - m_affinity = arg; - } - break; - - case 1021: /* --cpu-priority */ - if (arg <= 5) { - m_priority = (int) arg; - } - break; - - case 4000: /* --api-port */ - if (arg <= 65536) { - m_apiPort = (int) arg; - } - break; - - default: - break; - } - - return true; -} - - -bool Options::parseBoolean(int key, bool enable) -{ - switch (key) { - case 'k': /* --keepalive */ - m_pools.back()->setKeepAlive(enable); - break; - - case 'B': /* --background */ - m_background = enable; - m_colors = enable ? false : m_colors; - break; - - case 'S': /* --syslog */ - m_syslog = enable; - m_colors = enable ? false : m_colors; - break; - - case 1002: /* --no-color */ - m_colors = enable; - break; - - case 1005: /* --safe */ - m_safe = enable; - break; - - case 1006: /* --nicehash */ - m_pools.back()->setNicehash(enable); - break; - - case 1009: /* --no-huge-pages */ - m_hugePages = enable; - break; - - case 2000: /* colors */ - m_colors = enable; - break; - - case 5000: /* --dry-run */ - m_dryRun = enable; - break; - - default: - break; - } - - return true; -} - - -Url *Options::parseUrl(const char *arg) const -{ - auto url = new Url(arg); - if (!url->isValid()) { - delete url; - return nullptr; - } - - return url; -} - - -void Options::adjust() -{ - for (Url *url : m_pools) { - url->adjust(m_algo); - } -} - - -void Options::parseConfig(const char *fileName) -{ - rapidjson::Document doc; - if (!getJSON(fileName, doc)) { - return; - } - - for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) { - parseJSON(&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(&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(&api_options[i], api); - } - } -} - - -void Options::parseJSON(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 && value.IsString()) { - parseArg(option->val, value.GetString()); - } - else if (option->has_arg && value.IsInt64()) { - parseArg(option->val, value.GetUint64()); - } - else if (!option->has_arg && value.IsBool()) { - parseBoolean(option->val, value.IsTrue()); - } -} - - -void Options::showUsage(int status) const -{ - if (status) { - fprintf(stderr, "Try \"" APP_ID "\" --help' for more information.\n"); - } - else { - printf(usage); - } -} - - -void Options::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) - " i386" -# elif defined(__x86_64__) || defined(_M_AMD64) - " x86_64" -# endif - -# if defined(__AES__) || defined(_MSC_VER) - " AES-NI" -# endif - "\n"); - - printf("\nlibuv/%s\n", uv_version_string()); - -# ifndef XMRIG_NO_HTTPD - printf("libmicrohttpd/%s\n", MHD_get_version()); -# endif -} - - -bool Options::setAlgo(const char *algo) -{ - for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) { - if (algo_names[i] && !strcmp(algo, algo_names[i])) { - m_algo = (int) i; - break; - } - -# ifndef XMRIG_NO_AEON - if (i == ARRAY_SIZE(algo_names) - 1 && !strcmp(algo, "cryptonight-light")) { - m_algo = xmrig::ALGO_CRYPTONIGHT_LITE; - break; - } -# endif - - if (i == ARRAY_SIZE(algo_names) - 1) { - showUsage(1); - return false; - } - } - - return true; -} - - -int Options::getAlgoVariant() const -{ -# ifndef XMRIG_NO_AEON - if (m_algo == xmrig::ALGO_CRYPTONIGHT_LITE) { - return getAlgoVariantLite(); - } -# endif - - if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::hasAES() ? AV1_AESNI : AV3_SOFT_AES; - } - - if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) { - return m_algoVariant + 2; - } - - return m_algoVariant; -} - - -#ifndef XMRIG_NO_AEON -int Options::getAlgoVariantLite() const -{ - if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) { - return Cpu::hasAES() ? AV2_AESNI_DOUBLE : AV4_SOFT_AES_DOUBLE; - } - - if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) { - return m_algoVariant + 2; - } - - return m_algoVariant; -} -#endif diff --git a/src/Options.h b/src/Options.h deleted file mode 100644 index e29059ec..00000000 --- a/src/Options.h +++ /dev/null @@ -1,133 +0,0 @@ -/* 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 __OPTIONS_H__ -#define __OPTIONS_H__ - - -#include -#include - - -#include "rapidjson/fwd.h" - - -class Url; -struct option; - - -class Options -{ -public: - enum AlgoVariant { - AV0_AUTO, - AV1_AESNI, - AV2_AESNI_DOUBLE, - AV3_SOFT_AES, - AV4_SOFT_AES_DOUBLE, - AV_MAX - }; - - static inline Options* i() { return m_self; } - static Options *parse(int argc, char **argv); - - inline bool background() const { return m_background; } - inline bool colors() const { return m_colors; } - inline bool doubleHash() const { return m_doubleHash; } - inline bool dryRun() const { return m_dryRun; } - inline bool hugePages() const { return m_hugePages; } - inline bool syslog() const { return m_syslog; } - inline const char *apiToken() const { return m_apiToken; } - inline const char *apiWorkerId() const { return m_apiWorkerId; } - inline const char *logFile() const { return m_logFile; } - inline const char *userAgent() const { return m_userAgent; } - inline const std::vector &pools() const { return m_pools; } - inline int algo() const { return m_algo; } - inline int algoVariant() const { return m_algoVariant; } - inline int apiPort() const { return m_apiPort; } - inline int donateLevel() const { return m_donateLevel; } - inline int printTime() const { return m_printTime; } - inline int priority() const { return m_priority; } - inline int retries() const { return m_retries; } - inline int retryPause() const { return m_retryPause; } - inline int threads() const { return m_threads; } - inline int64_t affinity() const { return m_affinity; } - inline void setColors(bool colors) { m_colors = colors; } - - inline static void release() { delete m_self; } - - const char *algoName() const; - -private: - Options(int argc, char **argv); - ~Options(); - - inline bool isReady() const { return m_ready; } - - static Options *m_self; - - bool getJSON(const char *fileName, rapidjson::Document &doc); - bool parseArg(int key, const char *arg); - bool parseArg(int key, uint64_t arg); - bool parseBoolean(int key, bool enable); - Url *parseUrl(const char *arg) const; - void adjust(); - void parseConfig(const char *fileName); - void parseJSON(const struct option *option, const rapidjson::Value &object); - void showUsage(int status) const; - void showVersion(void); - - bool setAlgo(const char *algo); - - int getAlgoVariant() const; -# ifndef XMRIG_NO_AEON - int getAlgoVariantLite() const; -# endif - - bool m_background; - bool m_colors; - bool m_doubleHash; - bool m_dryRun; - bool m_hugePages; - bool m_ready; - bool m_safe; - bool m_syslog; - char *m_apiToken; - char *m_apiWorkerId; - char *m_logFile; - char *m_userAgent; - int m_algo; - int m_algoVariant; - int m_apiPort; - int m_donateLevel; - int m_maxCpuUsage; - int m_printTime; - int m_priority; - int m_retries; - int m_retryPause; - int m_threads; - int64_t m_affinity; - std::vector m_pools; -}; - -#endif /* __OPTIONS_H__ */ diff --git a/src/Summary.cpp b/src/Summary.cpp index 2d93f429..e960dd8d 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 @@ -27,16 +27,17 @@ #include +#include "common/log/Log.h" +#include "common/net/Pool.h" +#include "core/Config.h" +#include "core/Controller.h" #include "Cpu.h" -#include "log/Log.h" #include "Mem.h" -#include "net/Url.h" -#include "Options.h" #include "Summary.h" #include "version.h" -static void print_versions() +static void print_versions(xmrig::Config *config) { char buf[16]; @@ -51,26 +52,27 @@ static void print_versions() # endif - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s" : " * VERSIONS: XMRig/%s libuv/%s%s", + Log::i()->text(config->isColors() ? "\x1B[01;32m * \x1B[01;37mVERSIONS: \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s" : " * VERSIONS: XMRig/%s libuv/%s%s", APP_VERSION, uv_version_string(), buf); } -static void print_memory() { - if (Options::i()->colors()) { - Log::i()->text("\x1B[01;32m * \x1B[01;37mHUGE PAGES: %s, %s", - Mem::isHugepagesAvailable() ? "\x1B[01;32mavailable" : "\x1B[01;31munavailable", - Mem::isHugepagesEnabled() ? "\x1B[01;32menabled" : "\x1B[01;31mdisabled"); +static void print_memory(xmrig::Config *config) { +# ifdef _WIN32 + if (config->isColors()) { + Log::i()->text("\x1B[01;32m * \x1B[01;37mHUGE PAGES: %s", + Mem::isHugepagesAvailable() ? "\x1B[01;32mavailable" : "\x1B[01;31munavailable"); } else { - Log::i()->text(" * HUGE PAGES: %s, %s", Mem::isHugepagesAvailable() ? "available" : "unavailable", Mem::isHugepagesEnabled() ? "enabled" : "disabled"); + Log::i()->text(" * HUGE PAGES: %s", Mem::isHugepagesAvailable() ? "available" : "unavailable"); } +# endif } -static void print_cpu() +static void print_cpu(xmrig::Config *config) { - if (Options::i()->colors()) { + if (config->isColors()) { Log::i()->text("\x1B[01;32m * \x1B[01;37mCPU: %s (%d) %sx64 %sAES-NI", Cpu::brand(), Cpu::sockets(), @@ -89,60 +91,71 @@ static void print_cpu() } -static void print_threads() +static void print_threads(xmrig::Config *config) { - char buf[32]; - if (Options::i()->affinity() != -1L) { - snprintf(buf, 32, ", affinity=0x%" PRIX64, Options::i()->affinity()); + if (config->threadsMode() != xmrig::Config::Advanced) { + char buf[32]; + if (config->affinity() != -1L) { + snprintf(buf, 32, ", affinity=0x%" PRIX64, config->affinity()); + } + else { + buf[0] = '\0'; + } + + Log::i()->text(config->isColors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, %sdonate=%d%%%s" : " * THREADS: %d, %s, av=%d, %sdonate=%d%%%s", + config->threadsCount(), + config->algorithm().name(), + config->algoVariant(), + config->isColors() && config->donateLevel() == 0 ? "\x1B[01;31m" : "", + config->donateLevel(), + buf); } else { - buf[0] = '\0'; + Log::i()->text(config->isColors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, %sdonate=%d%%" : " * THREADS: %d, %s, %sdonate=%d%%", + config->threadsCount(), + config->algorithm().name(), + config->isColors() && config->donateLevel() == 0 ? "\x1B[01;31m" : "", + config->donateLevel()); } - - Log::i()->text(Options::i()->colors() ? "\x1B[01;32m * \x1B[01;37mTHREADS: \x1B[01;36m%d\x1B[01;37m, %s, av=%d, %sdonate=%d%%%s" : " * THREADS: %d, %s, av=%d, %sdonate=%d%%%s", - Options::i()->threads(), - Options::i()->algoName(), - Options::i()->algoVariant(), - Options::i()->colors() && Options::i()->donateLevel() == 0 ? "\x1B[01;31m" : "", - Options::i()->donateLevel(), - buf); } -static void print_pools() +static void print_pools(xmrig::Config *config) { - const std::vector &pools = Options::i()->pools(); + const std::vector &pools = config->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", + Log::i()->text(config->isColors() ? "\x1B[01;32m * \x1B[01;37mPOOL #%d: \x1B[01;36m%s" : " * POOL #%d: %s", i + 1, - pools[i]->host(), - pools[i]->port()); + pools[i].url() + ); } # 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()); + for (const Pool &pool : pools) { + pool.print(); } # endif } #ifndef XMRIG_NO_API -static void print_api() +static void print_api(xmrig::Config *config) { - if (Options::i()->apiPort() == 0) { + const int port = config->apiPort(); + if (port == 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()); + Log::i()->text(config->isColors() ? "\x1B[01;32m * \x1B[01;37mAPI BIND: \x1B[01;36m%s:%d" : " * API BIND: %s:%d", + config->isApiIPv6() ? "[::]" : "0.0.0.0", port); } #endif -static void print_commands() +static void print_commands(xmrig::Config *config) { - if (Options::i()->colors()) { + if (config->isColors()) { 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"); } else { @@ -151,19 +164,19 @@ static void print_commands() } -void Summary::print() +void Summary::print(xmrig::Controller *controller) { - print_versions(); - print_memory(); - print_cpu(); - print_threads(); - print_pools(); + print_versions(controller->config()); + print_memory(controller->config()); + print_cpu(controller->config()); + print_threads(controller->config()); + print_pools(controller->config()); # ifndef XMRIG_NO_API - print_api(); + print_api(controller->config()); # endif - print_commands(); + print_commands(controller->config()); } diff --git a/src/Summary.h b/src/Summary.h index 3f64fd60..f07dba35 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 @@ -25,10 +25,15 @@ #define __SUMMARY_H__ +namespace xmrig { + class Controller; +} + + class Summary { public: - static void print(); + static void print(xmrig::Controller *controller); }; diff --git a/src/api/Api.cpp b/src/api/Api.cpp index 729ebccd..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,43 +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::tick(const Hashrate *hashrate) -{ - if (!m_state) { + if (!m_router) { + reply.status = 500; return; } - uv_mutex_lock(&m_mutex); - m_state->tick(hashrate); - uv_mutex_unlock(&m_mutex); + if (req.method() == xmrig::HttpRequest::Get) { + return m_router->get(req, reply); + } + + 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 72c65c3c..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 @@ -28,24 +28,29 @@ #include -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 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/ApiState.cpp b/src/api/ApiRouter.cpp similarity index 54% rename from src/api/ApiState.cpp rename to src/api/ApiRouter.cpp index c963a1d6..07e425f1 100644 --- a/src/api/ApiState.cpp +++ b/src/api/ApiRouter.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 @@ -32,23 +32,23 @@ #endif -#include "api/ApiState.h" +#include "api/ApiRouter.h" +#include "common/api/HttpReply.h" +#include "common/api/HttpRequest.h" +#include "common/crypto/keccak.h" +#include "common/net/Job.h" +#include "common/Platform.h" +#include "core/Config.h" +#include "core/Controller.h" #include "Cpu.h" +#include "interfaces/IThread.h" #include "Mem.h" -#include "net/Job.h" -#include "Options.h" -#include "Platform.h" #include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" #include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" #include "version.h" #include "workers/Hashrate.h" - - -extern "C" -{ -#include "crypto/c_keccak.h" -} +#include "workers/Workers.h" static inline double normalize(double d) @@ -61,34 +61,42 @@ static inline double normalize(double d) } -ApiState::ApiState() +ApiRouter::ApiRouter(xmrig::Controller *controller) : + m_controller(controller) { - m_threads = Options::i()->threads(); - m_hashrate = new double[m_threads * 3](); - - memset(m_totalHashrate, 0, sizeof(m_totalHashrate)); memset(m_workerId, 0, sizeof(m_workerId)); - if (Options::i()->apiWorkerId()) { - strncpy(m_workerId, Options::i()->apiWorkerId(), sizeof(m_workerId) - 1); - } - else { - gethostname(m_workerId, sizeof(m_workerId) - 1); - } - + setWorkerId(controller->config()->apiWorkerId()); genId(); } -ApiState::~ApiState() +ApiRouter::~ApiRouter() { - delete [] m_hashrate; } -char *ApiState::get(const char *url, int *status) const +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); @@ -97,43 +105,47 @@ char *ApiState::get(const char *url, int *status) const getResults(doc); getConnection(doc); - return finalize(doc); + return finalize(reply, doc); } -void ApiState::tick(const Hashrate *hashrate) +void ApiRouter::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) { - for (int i = 0; i < m_threads; ++i) { - m_hashrate[i * 3] = hashrate->calc((size_t) i, Hashrate::ShortInterval); - m_hashrate[i * 3 + 1] = hashrate->calc((size_t) i, Hashrate::MediumInterval); - m_hashrate[i * 3 + 2] = hashrate->calc((size_t) i, Hashrate::LargeInterval); + if (req.method() == xmrig::HttpRequest::Put && req.match("/1/config")) { + m_controller->config()->reload(req.body()); + return; } - m_totalHashrate[0] = hashrate->calc(Hashrate::ShortInterval); - m_totalHashrate[1] = hashrate->calc(Hashrate::MediumInterval); - m_totalHashrate[2] = hashrate->calc(Hashrate::LargeInterval); - m_highestHashrate = hashrate->highest(); + reply.status = 404; } -void ApiState::tick(const NetworkState &network) +void ApiRouter::tick(const NetworkState &network) { m_network = network; } -char *ApiState::finalize(rapidjson::Document &doc) const +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(0, 4096); rapidjson::PrettyWriter writer(buffer); writer.SetMaxDecimalPlaces(10); doc.Accept(writer); - return strdup(buffer.GetString()); + reply.status = 200; + reply.buf = strdup(buffer.GetString()); + reply.size = buffer.GetSize(); } -void ApiState::genId() +void ApiRouter::genId() { memset(m_id, 0, sizeof(m_id)); @@ -154,7 +166,7 @@ void ApiState::genId() memcpy(input, interfaces[i].phys_addr, addrSize); memcpy(input + addrSize, APP_KIND, strlen(APP_KIND)); - keccak(input, static_cast(inSize), hash, sizeof(hash)); + xmrig::keccak(input, inSize, hash); Job::toHex(hash, 8, m_id); delete [] input; @@ -166,7 +178,7 @@ void ApiState::genId() } -void ApiState::getConnection(rapidjson::Document &doc) const +void ApiRouter::getConnection(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -181,7 +193,7 @@ void ApiState::getConnection(rapidjson::Document &doc) const } -void ApiState::getHashrate(rapidjson::Document &doc) const +void ApiRouter::getHashrate(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -189,34 +201,36 @@ void ApiState::getHashrate(rapidjson::Document &doc) const rapidjson::Value total(rapidjson::kArrayType); rapidjson::Value threads(rapidjson::kArrayType); - for (int i = 0; i < 3; ++i) { - total.PushBack(normalize(m_totalHashrate[i]), allocator); - } + const Hashrate *hr = Workers::hashrate(); - for (int i = 0; i < m_threads * 3; i += 3) { + 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(m_hashrate[i]), allocator); - thread.PushBack(normalize(m_hashrate[i + 1]), allocator); - thread.PushBack(normalize(m_hashrate[i + 2]), allocator); + 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(m_highestHashrate), allocator); + hashrate.AddMember("total", total, allocator); + hashrate.AddMember("highest", normalize(hr->highest()), allocator); hashrate.AddMember("threads", threads, allocator); doc.AddMember("hashrate", hashrate, allocator); } -void ApiState::getIdentify(rapidjson::Document &doc) const +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 ApiState::getMiner(rapidjson::Document &doc) const +void ApiRouter::getMiner(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -230,13 +244,13 @@ void ApiState::getMiner(rapidjson::Document &doc) const doc.AddMember("kind", APP_KIND, allocator); doc.AddMember("ua", rapidjson::StringRef(Platform::userAgent()), allocator); doc.AddMember("cpu", cpu, allocator); - doc.AddMember("algo", rapidjson::StringRef(Options::i()->algoName()), allocator); - doc.AddMember("hugepages", Mem::isHugepagesEnabled(), allocator); - doc.AddMember("donate_level", Options::i()->donateLevel(), 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 ApiState::getResults(rapidjson::Document &doc) const +void ApiRouter::getResults(rapidjson::Document &doc) const { auto &allocator = doc.GetAllocator(); @@ -258,3 +272,57 @@ void ApiState::getResults(rapidjson::Document &doc) const 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/ApiState.h b/src/api/ApiRouter.h similarity index 59% rename from src/api/ApiState.h rename to src/api/ApiRouter.h index 7ecca36d..3ed458d4 100644 --- a/src/api/ApiState.h +++ b/src/api/ApiRouter.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,55 @@ * along with this program. If not, see . */ -#ifndef __APISTATE_H__ -#define __APISTATE_H__ +#ifndef __APIROUTER_H__ +#define __APIROUTER_H__ #include "api/NetworkState.h" +#include "interfaces/IControllerListener.h" #include "rapidjson/fwd.h" class Hashrate; -class ApiState +namespace xmrig { + class Controller; + class HttpReply; + class HttpRequest; +} + + +class ApiRouter : public xmrig::IControllerListener { public: - ApiState(); - ~ApiState(); + ApiRouter(xmrig::Controller *controller); + ~ApiRouter(); + + void get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const; + void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply); - char *get(const char *url, int *status) const; - void tick(const Hashrate *hashrate); void tick(const NetworkState &results); +protected: + void onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) override; + private: - char *finalize(rapidjson::Document &doc) const; + void finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const; void genId(); void getConnection(rapidjson::Document &doc) const; void getHashrate(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[17]; char m_workerId[128]; - double *m_hashrate; - double m_highestHashrate; - double m_totalHashrate[3]; - int m_threads; NetworkState m_network; + xmrig::Controller *m_controller; }; -#endif /* __APISTATE_H__ */ +#endif /* __APIROUTER_H__ */ diff --git a/src/api/Httpd.cpp b/src/api/Httpd.cpp deleted file mode 100644 index a0c591c4..00000000 --- a/src/api/Httpd.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* 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 "api/Httpd.h" -#include "log/Log.h" - - -Httpd::Httpd(int port, const char *accessToken) : - m_accessToken(accessToken), - m_port(port), - m_daemon(nullptr) -{ -} - - -bool Httpd::start() -{ - if (!m_port) { - return false; - } - - unsigned int flags = MHD_USE_SELECT_INTERNALLY; - -# if MHD_VERSION >= 0x00093500 - if (MHD_is_feature_supported(MHD_FEATURE_EPOLL)) { - flags = MHD_USE_EPOLL_LINUX_ONLY | MHD_USE_EPOLL_INTERNALLY_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; - } - - return true; -} - - -int Httpd::auth(const char *header) -{ - if (!m_accessToken) { - return MHD_HTTP_OK; - } - - if (m_accessToken && !header) { - return MHD_HTTP_UNAUTHORIZED; - } - - const size_t size = strlen(header); - if (size < 8 || strlen(m_accessToken) != size - 7 || memcmp("Bearer ", header, 7) != 0) { - return MHD_HTTP_FORBIDDEN; - } - - return strncmp(m_accessToken, header + 7, strlen(m_accessToken)) == 0 ? MHD_HTTP_OK : MHD_HTTP_FORBIDDEN; -} - - -int Httpd::done(MHD_Connection *connection, 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"); - MHD_add_response_header(rsp, "Access-Control-Allow-Headers", "Authorization"); - - const int ret = MHD_queue_response(connection, status, rsp); - MHD_destroy_response(rsp); - return ret; -} - - -int Httpd::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) -{ - if (strcmp(method, "OPTIONS") == 0) { - return done(connection, MHD_HTTP_OK, nullptr); - } - - if (strcmp(method, "GET") != 0) { - return MHD_NO; - } - - int status = static_cast(cls)->auth(MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Authorization")); - if (status != MHD_HTTP_OK) { - return done(connection, status, nullptr); - } - - char *buf = Api::get(url, &status); - if (buf == nullptr) { - return MHD_NO; - } - - MHD_Response *rsp = MHD_create_response_from_buffer(strlen(buf), (void*) buf, MHD_RESPMEM_MUST_FREE); - return done(connection, status, rsp); -} 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/Console.cpp b/src/common/Console.cpp similarity index 90% rename from src/Console.cpp rename to src/common/Console.cpp index 3d95ada4..350fb139 100644 --- a/src/Console.cpp +++ b/src/common/Console.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,7 +22,7 @@ */ -#include "Console.h" +#include "common/Console.h" #include "interfaces/IConsoleListener.h" diff --git a/src/Console.h b/src/common/Console.h similarity index 88% rename from src/Console.h rename to src/common/Console.h index bde95d7d..7f2e3cc9 100644 --- a/src/Console.h +++ b/src/common/Console.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 diff --git a/src/Platform.cpp b/src/common/Platform.cpp similarity index 89% rename from src/Platform.cpp rename to src/common/Platform.cpp index 4ddb1429..52b55987 100644 --- a/src/Platform.cpp +++ b/src/common/Platform.cpp @@ -29,16 +29,16 @@ #include "Platform.h" -char *Platform::m_defaultConfigName = nullptr; -char *Platform::m_userAgent = nullptr; +char Platform::m_defaultConfigName[520] = { 0 }; +xmrig::c_str Platform::m_userAgent; const char *Platform::defaultConfigName() { size_t size = 520; - if (m_defaultConfigName == nullptr) { - m_defaultConfigName = new char[size]; + if (*m_defaultConfigName) { + return m_defaultConfigName; } if (uv_exepath(m_defaultConfigName, &size) < 0) { @@ -58,5 +58,6 @@ const char *Platform::defaultConfigName() } } + *m_defaultConfigName = '\0'; return nullptr; } diff --git a/src/Platform.h b/src/common/Platform.h similarity index 83% rename from src/Platform.h rename to src/common/Platform.h index 87c8cc4d..8704604a 100644 --- a/src/Platform.h +++ b/src/common/Platform.h @@ -25,20 +25,26 @@ #define __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 release(); static void setProcessPriority(int priority); static void setThreadPriority(int priority); - static inline const char *userAgent() { return m_userAgent; } + static inline const char *userAgent() { return m_userAgent.data(); } private: - static char *m_defaultConfigName; - static char *m_userAgent; + static char m_defaultConfigName[520]; + static xmrig::c_str m_userAgent; }; diff --git a/src/Platform_mac.cpp b/src/common/Platform_mac.cpp similarity index 82% rename from src/Platform_mac.cpp rename to src/common/Platform_mac.cpp index ba541f1d..b8181cc4 100644 --- a/src/Platform_mac.cpp +++ b/src/common/Platform_mac.cpp @@ -22,6 +22,8 @@ */ +#include +#include #include #include #include @@ -53,15 +55,24 @@ static inline char *createUserAgent() } -void Platform::init(const char *userAgent) +bool Platform::setThreadAffinity(uint64_t cpu_id) { - m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); + 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::release() +void Platform::init(const char *userAgent) { - delete [] m_userAgent; + if (userAgent) { + m_userAgent = userAgent; + } + else { + m_userAgent = createUserAgent(); + } } diff --git a/src/Platform_unix.cpp b/src/common/Platform_unix.cpp similarity index 77% rename from src/Platform_unix.cpp rename to src/common/Platform_unix.cpp index c0589307..63cd1c8b 100644 --- a/src/Platform_unix.cpp +++ b/src/common/Platform_unix.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 @@ -21,6 +21,14 @@ * along with this program. If not, see . */ +#ifdef __FreeBSD__ +# include +# include +# include +# include +#endif + + #include #include #include @@ -37,6 +45,11 @@ #endif +#ifdef __FreeBSD__ +typedef cpuset_t cpu_set_t; +#endif + + static inline char *createUserAgent() { const size_t max = 160; @@ -63,15 +76,28 @@ static inline char *createUserAgent() } -void Platform::init(const char *userAgent) +bool Platform::setThreadAffinity(uint64_t cpu_id) { - m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); + 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::release() +void Platform::init(const char *userAgent) { - delete [] m_userAgent; + if (userAgent) { + m_userAgent = userAgent; + } + else { + m_userAgent = createUserAgent(); + } } diff --git a/src/Platform_win.cpp b/src/common/Platform_win.cpp similarity index 91% rename from src/Platform_win.cpp rename to src/common/Platform_win.cpp index 880bdd98..47f41867 100644 --- a/src/Platform_win.cpp +++ b/src/common/Platform_win.cpp @@ -27,9 +27,11 @@ #include +#include "log/Log.h" #include "Platform.h" #include "version.h" + #ifdef XMRIG_NVIDIA_PROJECT # include "nvidia/cryptonight.h" #endif @@ -82,16 +84,24 @@ static inline char *createUserAgent() } -void Platform::init(const char *userAgent) +bool Platform::setThreadAffinity(uint64_t cpu_id) { - m_userAgent = userAgent ? strdup(userAgent) : createUserAgent(); + 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::release() +void Platform::init(const char *userAgent) { - delete [] m_defaultConfigName; - delete [] m_userAgent; + if (userAgent) { + m_userAgent = userAgent; + } + else { + m_userAgent = createUserAgent(); + } } @@ -131,7 +141,6 @@ void Platform::setProcessPriority(int priority) } - void Platform::setThreadPriority(int priority) { if (priority == -1) { 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/xmrig.h b/src/common/api/HttpReply.h similarity index 79% rename from src/xmrig.h rename to src/common/api/HttpReply.h index 103e8a68..6a6cb802 100644 --- a/src/xmrig.h +++ b/src/common/api/HttpReply.h @@ -7,6 +7,7 @@ * 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 @@ -21,27 +22,32 @@ * along with this program. If not, see . */ -#ifndef __XMRIG_H__ -#define __XMRIG_H__ +#ifndef __HTTPREPLY_H__ +#define __HTTPREPLY_H__ -namespace xmrig +#include + + +namespace xmrig { + + +class HttpReply { +public: + HttpReply() : + buf(nullptr), + status(200), + size(0) + {} - -enum Algo { - ALGO_CRYPTONIGHT, /* CryptoNight (Monero) */ - ALGO_CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */ + char *buf; + int status; + size_t size; }; -enum Variant { - VARIANT_AUTO = -1, - VARIANT_NONE = 0, - VARIANT_V1 = 1 -}; - -} /* xmrig */ +} /* namespace xmrig */ -#endif /* __XMRIG_H__ */ +#endif /* __HTTPREPLY_H__ */ diff --git a/src/common/api/HttpRequest.cpp b/src/common/api/HttpRequest.cpp new file mode 100644 index 00000000..01245dfc --- /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"); + + 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/api/Httpd.h b/src/common/api/Httpd.h similarity index 76% rename from src/api/Httpd.h rename to src/common/api/Httpd.h index 30618e2a..adec1d71 100644 --- a/src/api/Httpd.h +++ b/src/common/api/Httpd.h @@ -33,21 +33,38 @@ struct MHD_Daemon; struct MHD_Response; +class UploadCtx; + + +namespace xmrig { + class HttpRequest; +} + + class Httpd { public: - Httpd(int port, const char *accessToken); + Httpd(int port, const char *accessToken, bool IPv6, bool restricted); + ~Httpd(); bool start(); private: - int auth(const char *header); + constexpr static const int kIdleInterval = 200; + constexpr static const int kActiveInterval = 25; - static int done(MHD_Connection *connection, int status, MHD_Response *rsp); - static int handler(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls); + 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..5eaf68fd --- /dev/null +++ b/src/common/config/CommonConfig.cpp @@ -0,0 +1,343 @@ +/* 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/config/CommonConfig.h" +#include "common/log/Log.h" +#include "donate.h" +#include "rapidjson/document.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/prettywriter.h" + + +xmrig::CommonConfig::CommonConfig() : + m_adjusted(false), + m_apiIPv6(false), + m_apiRestricted(true), + m_background(false), + m_colors(true), + 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 +} + + +xmrig::CommonConfig::~CommonConfig() +{ +} + + +bool xmrig::CommonConfig::finalize() +{ + if (m_state == ReadyState) { + return true; + } + + if (m_state == ErrorState) { + return false; + } + + if (!m_algorithm.isValid()) { + m_algorithm.setAlgo(CRYPTONIGHT); + } + + for (Pool &pool : m_pools) { + pool.adjust(m_algorithm.algo()); + + if (pool.isValid() && pool.algorithm().isValid()) { + 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; + +# 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; + + case ApiRestrictedKey: /* restricted */ + m_apiRestricted = enable; + + 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 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 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 ApiIPv6Key: /* --api-ipv6 */ + 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)); +} + + +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); + + fclose(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; +} + + +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..d54afe3a --- /dev/null +++ b/src/common/config/CommonConfig.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 __COMMONCONFIG_H__ +#define __COMMONCONFIG_H__ + + +#include + + +#include "common/net/Pool.h" +#include "common/utils/c_str.h" +#include "common/xmrig.h" +#include "interfaces/IConfig.h" + + +namespace xmrig { + + +class CommonConfig : public IConfig +{ +public: + CommonConfig(); + ~CommonConfig(); + + inline bool isApiIPv6() const { return m_apiIPv6; } + inline bool isApiRestricted() const { return m_apiRestricted; } + inline bool isBackground() const { return m_background; } + inline bool isColors() const { return m_colors; } + inline bool isSyslog() const { return m_syslog; } + inline const Algorithm &algorithm() const { return m_algorithm; } + 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 char *fileName() const override { return m_fileName.data(); } + +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; + bool save() override; + void setFileName(const char *fileName) override; + + Algorithm m_algorithm; + bool m_adjusted; + bool m_apiIPv6; + bool m_apiRestricted; + bool m_background; + bool m_colors; + 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_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..919ff00c --- /dev/null +++ b/src/common/config/ConfigLoader.cpp @@ -0,0 +1,312 @@ +/* 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 + + +#include "common/config/ConfigLoader.h" +#include "common/config/ConfigWatcher.h" +#include "common/net/Pool.h" +#include "common/Platform.h" +#include "core/ConfigCreator.h" +#include "core/ConfigLoader_platform.h" +#include "interfaces/IConfig.h" +#include "interfaces/IWatcherListener.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()) { + 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("libmicrohttpd/%s\n", MHD_get_version()); +# 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..bde35f23 --- /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/log/Log.h" +#include "core/ConfigCreator.h" +#include "interfaces/IWatcherListener.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/crypto/Algorithm.cpp b/src/common/crypto/Algorithm.cpp new file mode 100644 index 00000000..fce4d7b8 --- /dev/null +++ b/src/common/crypto/Algorithm.cpp @@ -0,0 +1,219 @@ +/* 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 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 }, + +# ifndef XMRIG_NO_AEON + { "cryptonight-lite", "cn-lite", 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 }, + { "cryptonight-lite/ipbc", "cn-lite/ipbc", xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_IPBC }, +# endif + +# ifndef XMRIG_NO_SUMO + { "cryptonight-heavy", "cn-heavy", xmrig::CRYPTONIGHT_HEAVY, xmrig::VARIANT_0 }, +# 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_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_lite_v7_xor", nullptr, xmrig::CRYPTONIGHT_LITE, xmrig::VARIANT_IPBC }, +}; +#endif + + +static const char *variants[] = { + "0", + "1", + "ipbc", + "xtl" +}; + + +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) +{ + if (m_algo == CRYPTONIGHT_HEAVY) { + m_variant = VARIANT_0; + return; + } + + 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) +{ + if (variant >= VARIANT_AUTO && variant <= VARIANT_XTL) { + m_variant = static_cast(variant); + } + else { + assert(false); + } +} + + +void xmrig::Algorithm::setAlgo(Algo algo) +{ + m_algo = algo; + + if (m_algo == CRYPTONIGHT_HEAVY) { + m_variant = VARIANT_0; + } +} + + +#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..bcf029d8 --- /dev/null +++ b/src/common/crypto/Algorithm.h @@ -0,0 +1,91 @@ +/* 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 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 __ALGORITHM_H__ +#define __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/crypto/c_keccak.c b/src/common/crypto/keccak.cpp similarity index 74% rename from src/crypto/c_keccak.c rename to src/common/crypto/keccak.cpp index 997db241..0219ce36 100644 --- a/src/crypto/c_keccak.c +++ b/src/common/crypto/keccak.cpp @@ -1,10 +1,35 @@ -// keccak.c -// 19-Nov-11 Markku-Juhani O. Saarinen -// A baseline Keccak (3rd round) implementation. +/* 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 @@ -26,7 +51,7 @@ const uint64_t keccakf_rndc[24] = // update the state with given number of rounds -void keccakf(uint64_t st[25], int rounds) +void xmrig::keccakf(uint64_t st[25], int rounds) { int i, j, round; uint64_t t, bc[5]; @@ -139,7 +164,8 @@ void keccakf(uint64_t st[25], int rounds) // compute a keccak hash (md) of given byte length from "in" typedef uint64_t state_t[25]; -void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) + +void xmrig::keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) { state_t st; uint8_t temp[144]; @@ -151,26 +177,24 @@ void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) memset(st, 0, sizeof(st)); for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { - for (i = 0; i < rsizw; i++) + for (i = 0; i < rsizw; i++) { st[i] ^= ((uint64_t *) in)[i]; - keccakf(st, KECCAK_ROUNDS); + } + + 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++) + for (i = 0; i < rsizw; i++) { st[i] ^= ((uint64_t *) temp)[i]; + } keccakf(st, KECCAK_ROUNDS); memcpy(md, st, mdlen); } - -void keccak1600(const uint8_t *in, int inlen, uint8_t *md) -{ - keccak(in, inlen, md, sizeof(state_t)); -} diff --git a/src/common/crypto/keccak.h b/src/common/crypto/keccak.h new file mode 100644 index 00000000..0413ec2d --- /dev/null +++ b/src/common/crypto/keccak.h @@ -0,0 +1,49 @@ +/* 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 KECCAK_H_ +#define 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); +} + +// update the state +void keccakf(uint64_t st[25], int norounds); + +} /* namespace xmrig */ + +#endif /* KECCAK_H_ */ diff --git a/src/log/ConsoleLog.cpp b/src/common/log/ConsoleLog.cpp similarity index 82% rename from src/log/ConsoleLog.cpp rename to src/common/log/ConsoleLog.cpp index 3656d48c..b7d187d1 100644 --- a/src/log/ConsoleLog.cpp +++ b/src/common/log/ConsoleLog.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 @@ -34,18 +34,18 @@ #endif -#include "log/ConsoleLog.h" -#include "log/Log.h" -#include "Options.h" +#include "common/log/ConsoleLog.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" -ConsoleLog::ConsoleLog(bool colors) : - m_colors(colors), - m_stream(nullptr) +ConsoleLog::ConsoleLog(xmrig::Controller *controller) : + m_stream(nullptr), + m_controller(controller) { if (uv_tty_init(uv_default_loop(), &m_tty, 1, 0) < 0) { - Options::i()->setColors(false); - m_colors = false; + controller->config()->setColors(false); return; } @@ -78,7 +78,9 @@ void ConsoleLog::message(int level, const char* fmt, va_list args) # endif const char* color = nullptr; - if (m_colors) { + const bool colors = m_controller->config()->isColors(); + + if (colors) { switch (level) { case Log::ERR: color = Log::kCL_RED; @@ -109,9 +111,9 @@ void ConsoleLog::message(int level, const char* fmt, va_list args) stime.tm_hour, stime.tm_min, stime.tm_sec, - m_colors ? color : "", + colors ? color : "", fmt, - m_colors ? Log::kCL_N : "" + colors ? Log::kCL_N : "" ); print(args); @@ -120,7 +122,7 @@ void ConsoleLog::message(int level, const char* fmt, va_list args) void ConsoleLog::text(const char* fmt, va_list args) { - snprintf(m_fmt, sizeof(m_fmt) - 1, "%s%s\n", fmt, m_colors ? Log::kCL_N : ""); + snprintf(m_fmt, sizeof(m_fmt) - 1, "%s%s\n", fmt, m_controller->config()->isColors() ? Log::kCL_N : ""); print(args); } diff --git a/src/log/ConsoleLog.h b/src/common/log/ConsoleLog.h similarity index 82% rename from src/log/ConsoleLog.h rename to src/common/log/ConsoleLog.h index a04a27c5..6649be84 100644 --- a/src/log/ConsoleLog.h +++ b/src/common/log/ConsoleLog.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 @@ -31,10 +31,15 @@ #include "interfaces/ILogBackend.h" +namespace xmrig { + class Controller; +} + + class ConsoleLog : public ILogBackend { public: - ConsoleLog(bool colors); + ConsoleLog(xmrig::Controller *controller); void message(int level, const char *fmt, va_list args) override; void text(const char *fmt, va_list args) override; @@ -43,12 +48,12 @@ private: bool isWritable() const; void print(va_list args); - bool m_colors; char m_buf[512]; 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/log/FileLog.cpp b/src/common/log/FileLog.cpp similarity index 98% rename from src/log/FileLog.cpp rename to src/common/log/FileLog.cpp index 5eeb252c..c8eaf5f7 100644 --- a/src/log/FileLog.cpp +++ b/src/common/log/FileLog.cpp @@ -29,7 +29,7 @@ #include -#include "log/FileLog.h" +#include "common/log/FileLog.h" FileLog::FileLog(const char *fileName) diff --git a/src/log/FileLog.h b/src/common/log/FileLog.h similarity index 100% rename from src/log/FileLog.h rename to src/common/log/FileLog.h diff --git a/src/log/Log.cpp b/src/common/log/Log.cpp similarity index 84% rename from src/log/Log.cpp rename to src/common/log/Log.cpp index c6030f66..03237f03 100644 --- a/src/log/Log.cpp +++ b/src/common/log/Log.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,8 +29,8 @@ #include +#include "common/log/Log.h" #include "interfaces/ILogBackend.h" -#include "log/Log.h" Log *Log::m_self = nullptr; @@ -38,6 +38,8 @@ Log *Log::m_self = nullptr; void Log::message(Log::Level level, const char* fmt, ...) { + uv_mutex_lock(&m_mutex); + va_list args; va_list copy; va_start(args, fmt); @@ -49,11 +51,15 @@ void Log::message(Log::Level level, const char* fmt, ...) } 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); @@ -65,6 +71,8 @@ void Log::text(const char* fmt, ...) } va_end(args); + + uv_mutex_unlock(&m_mutex); } diff --git a/src/log/Log.h b/src/common/log/Log.h similarity index 72% rename from src/log/Log.h rename to src/common/log/Log.h index fd944d80..31600dc6 100644 --- a/src/log/Log.h +++ b/src/common/log/Log.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,6 +25,7 @@ #define __LOG_H__ +#include #include #include @@ -54,23 +55,43 @@ public: constexpr static const char* kCL_GRAY = "\x1B[90m"; # endif - static inline Log* i() { return m_self; } + static inline Log* i() { assert(m_self != nullptr); return m_self; } static inline void add(ILogBackend *backend) { i()->m_backends.push_back(backend); } - static inline void init() { if (!m_self) { m_self = new Log();} } - static inline void release() { delete m_self; } + static inline void init() { if (!m_self) { new Log(); } } + static inline void release() { assert(m_self != nullptr); delete m_self; } void message(Level level, const char* fmt, ...); void text(const char* fmt, ...); private: - inline Log() {} + 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 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(Log::ERR, x, ##__VA_ARGS__) #define LOG_WARN(x, ...) Log::i()->message(Log::WARNING, x, ##__VA_ARGS__) #define LOG_NOTICE(x, ...) Log::i()->message(Log::NOTICE, x, ##__VA_ARGS__) diff --git a/src/log/SysLog.cpp b/src/common/log/SysLog.cpp similarity index 97% rename from src/log/SysLog.cpp rename to src/common/log/SysLog.cpp index f9b16cca..70879c33 100644 --- a/src/log/SysLog.cpp +++ b/src/common/log/SysLog.cpp @@ -25,7 +25,7 @@ #include -#include "log/SysLog.h" +#include "common/log/SysLog.h" #include "version.h" diff --git a/src/log/SysLog.h b/src/common/log/SysLog.h similarity index 100% rename from src/log/SysLog.h rename to src/common/log/SysLog.h diff --git a/src/net/Client.cpp b/src/common/net/Client.cpp similarity index 68% rename from src/net/Client.cpp rename to src/common/net/Client.cpp index 9e6758e3..921fa618 100644 --- a/src/net/Client.cpp +++ b/src/common/net/Client.cpp @@ -29,29 +29,23 @@ #include +#include "common/log/Log.h" +#include "common/net/Client.h" #include "interfaces/IClientListener.h" -#include "log/Log.h" -#include "net/Client.h" -#include "net/Url.h" +#include "net/JobResult.h" #include "rapidjson/document.h" #include "rapidjson/error/en.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" -#ifdef XMRIG_PROXY_PROJECT -# include "proxy/JobResult.h" -#else -# include "net/JobResult.h" -#endif - - #ifdef _MSC_VER # define strncasecmp(x,y,z) _strnicmp(x,y,z) #endif int64_t Client::m_sequence = 1; +xmrig::Storage Client::m_storage; Client::Client(int id, const char *agent, IClientListener *listener) : @@ -60,20 +54,26 @@ Client::Client(int id, const char *agent, IClientListener *listener) : 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_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 = this; + m_resolver.data = m_storage.ptr(m_key); m_hints.ai_family = AF_UNSPEC; m_hints.ai_socktype = SOCK_STREAM; @@ -81,11 +81,6 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_recvBuf.base = m_buf; m_recvBuf.len = sizeof(m_buf); - -# ifndef XMRIG_PROXY_PROJECT - m_keepAliveTimer.data = this; - uv_timer_init(uv_default_loop(), &m_keepAliveTimer); -# endif } @@ -97,7 +92,7 @@ Client::~Client() void Client::connect() { - resolve(m_url.host()); + resolve(m_pool.host()); } @@ -106,10 +101,10 @@ void Client::connect() * * @param url */ -void Client::connect(const Url *url) +void Client::connect(const Pool &url) { - setUrl(url); - resolve(m_url.host()); + setPool(url); + connect(); } @@ -122,34 +117,34 @@ void Client::deleteLater() m_listener = nullptr; if (!disconnect()) { - delete this; + m_storage.remove(m_key); } } -void Client::setUrl(const Url *url) +void Client::setPool(const Pool &pool) { - if (!url || !url->isValid()) { + if (!pool.isValid()) { return; } - m_url = url; + m_pool = pool; } void Client::tick(uint64_t now) { - if (m_expire == 0 || now < m_expire) { - return; - } - if (m_state == ConnectedState) { - LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port()); - close(); + 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_state == ConnectingState) { + if (m_expire && now > m_expire && m_state == ConnectingState) { connect(); } } @@ -157,12 +152,9 @@ void Client::tick(uint64_t now) bool Client::disconnect() { -# ifndef XMRIG_PROXY_PROJECT - uv_timer_stop(&m_keepAliveTimer); -# endif - - m_expire = 0; - m_failures = -1; + m_keepAlive = 0; + m_expire = 0; + m_failures = -1; return close(); } @@ -170,12 +162,14 @@ bool Client::disconnect() 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[9]; - char data[65]; + char *nonce = m_sendBuf; + char *data = m_sendBuf + 16; Job::toHex(reinterpret_cast(&result.nonce), 4, nonce); nonce[8] = '\0'; @@ -184,8 +178,24 @@ int64_t Client::submit(const JobResult &result) data[64] = '\0'; # endif - const size_t size = snprintf(m_sendBuf, sizeof(m_sendBuf), "{\"id\":%" PRIu64 ",\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n", - m_sequence, m_rpcId.data(), result.jobId.data(), nonce, data); + 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); @@ -193,7 +203,7 @@ int64_t Client::submit(const JobResult &result) m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff()); # endif - return send(size); + return send(doc); } @@ -242,13 +252,7 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } -# ifdef XMRIG_PROXY_PROJECT - Job job(m_id, m_url.variant()); - job.setClientId(m_rpcId); - job.setCoin(m_url.coin()); -# else - Job job(m_id, m_nicehash, m_url.algo(), m_url.variant()); -# endif + Job job(m_id, m_nicehash, m_pool.algorithm(), m_rpcId); if (!job.setId(params["job_id"].GetString())) { *code = 3; @@ -265,12 +269,26 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (params.HasMember("coin")) { - job.setCoin(params["coin"].GetString()); + if (params.HasMember("algo")) { + job.algorithm().parseAlgorithm(params["algo"].GetString()); } if (params.HasMember("variant")) { - job.setVariant(params["variant"].GetInt()); + const rapidjson::Value &variant = params["variant"]; + + if (variant.IsInt()) { + job.algorithm().parseVariant(variant.GetInt()); + } + else if (variant.IsString()){ + job.algorithm().parseVariant(variant.GetString()); + } + } + + if (!verifyAlgorithm(job.algorithm())) { + *code = 6; + + close(); + return false; } if (m_job != job) { @@ -283,8 +301,8 @@ bool Client::parseJob(const rapidjson::Value ¶ms, int *code) return false; } - if (!m_quiet) { - LOG_WARN("[%s:%u] duplicate job received, reconnect", m_url.host(), m_url.port()); + if (!isQuiet()) { + LOG_WARN("[%s] duplicate job received, reconnect", m_pool.url()); } close(); @@ -299,9 +317,7 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) return false; } -# ifndef XMRIG_PROXY_PROJECT - m_nicehash = m_url.isNicehash(); -# endif + m_nicehash = m_pool.isNicehash(); if (result.HasMember("extensions")) { parseExtensions(result["extensions"]); @@ -314,6 +330,27 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) } +bool Client::verifyAlgorithm(const xmrig::Algorithm &algorithm) const +{ + 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); @@ -327,8 +364,8 @@ int Client::resolve(const char *host) const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, nullptr, &m_hints); if (r) { - if (!m_quiet) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r)); + if (!isQuiet()) { + LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_pool.port(), uv_strerror(r)); } return 1; } @@ -337,11 +374,32 @@ int Client::resolve(const char *host) } +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_buf) - 2)) { + 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:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, m_sendBuf); + LOG_DEBUG("[%s] send (%d bytes): \"%s\"", m_pool.url(), size, m_sendBuf); if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); return -1; } @@ -379,14 +437,14 @@ void Client::connect(sockaddr *addr) { setState(ConnectingState); - reinterpret_cast(addr)->sin_port = htons(m_url.port()); + reinterpret_cast(addr)->sin_port = htons(m_pool.port()); delete m_socket; uv_connect_t *req = new uv_connect_t; - req->data = this; + req->data = m_storage.ptr(m_key); m_socket = new uv_tcp_t; - m_socket->data = this; + m_socket->data = m_storage.ptr(m_key); uv_tcp_init(uv_default_loop(), m_socket); uv_tcp_nodelay(m_socket, 1); @@ -401,38 +459,35 @@ void Client::connect(sockaddr *addr) void Client::login() { + using namespace rapidjson; m_results.clear(); - rapidjson::Document doc; - doc.SetObject(); - + Document doc(kObjectType); auto &allocator = doc.GetAllocator(); doc.AddMember("id", 1, allocator); doc.AddMember("jsonrpc", "2.0", allocator); doc.AddMember("method", "login", allocator); - rapidjson::Value params(rapidjson::kObjectType); - params.AddMember("login", rapidjson::StringRef(m_url.user()), allocator); - params.AddMember("pass", rapidjson::StringRef(m_url.password()), allocator); - params.AddMember("agent", rapidjson::StringRef(m_agent), 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); - doc.AddMember("params", params, allocator); - - rapidjson::StringBuffer buffer(0, 512); - rapidjson::Writer writer(buffer); - doc.Accept(writer); - - const size_t size = buffer.GetSize(); - if (size > (sizeof(m_buf) - 2)) { - return; + if (m_pool.rigId()) { + params.AddMember("rigid", StringRef(m_pool.rigId()), allocator); } - memcpy(m_sendBuf, buffer.GetString(), size); - m_sendBuf[size] = '\n'; - m_sendBuf[size + 1] = '\0'; + Value algo(kArrayType); - send(size + 1); + 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); } @@ -454,11 +509,11 @@ void Client::parse(char *line, size_t len) line[len - 1] = '\0'; - LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_url.host(), m_url.port(), len, line); + LOG_DEBUG("[%s] received (%d bytes): \"%s\"", m_pool.url(), len, line); if (len < 32 || line[0] != '{') { - if (!m_quiet) { - LOG_ERR("[%s:%u] JSON decode failed", m_url.host(), m_url.port()); + if (!isQuiet()) { + LOG_ERR("[%s] JSON decode failed", m_pool.url()); } return; @@ -466,8 +521,8 @@ void Client::parse(char *line, size_t len) rapidjson::Document doc; if (doc.ParseInsitu(line).HasParseError()) { - if (!m_quiet) { - LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_url.host(), m_url.port(), rapidjson::GetParseError_En(doc.GetParseError())); + if (!isQuiet()) { + LOG_ERR("[%s] JSON decode failed: \"%s\"", m_pool.url(), rapidjson::GetParseError_En(doc.GetParseError())); } return; @@ -489,6 +544,8 @@ void Client::parse(char *line, size_t len) void Client::parseExtensions(const rapidjson::Value &value) { + m_extensions = 0; + if (!value.IsArray()) { return; } @@ -498,8 +555,15 @@ void Client::parseExtensions(const rapidjson::Value &value) continue; } + if (strcmp(ext.GetString(), "algo") == 0) { + m_extensions |= AlgoExt; + continue; + } + if (strcmp(ext.GetString(), "nicehash") == 0) { + m_extensions |= NicehashExt; m_nicehash = true; + continue; } } } @@ -508,8 +572,8 @@ void Client::parseExtensions(const rapidjson::Value &value) void Client::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error) { if (error.IsObject()) { - if (!m_quiet) { - LOG_ERR("[%s:%u] error: \"%s\", code: %d", m_url.host(), m_url.port(), error["message"].GetString(), error["code"].GetInt()); + if (!isQuiet()) { + LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), error["message"].GetString(), error["code"].GetInt()); } return; } @@ -527,7 +591,7 @@ void Client::parseNotification(const char *method, const rapidjson::Value ¶m return; } - LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_url.host(), m_url.port(), method); + LOG_WARN("[%s] unsupported method: \"%s\"", m_pool.url(), method); } @@ -542,11 +606,11 @@ void Client::parseResponse(int64_t id, const rapidjson::Value &result, const rap m_listener->onResultAccepted(this, it->second, message); m_results.erase(it); } - else if (!m_quiet) { - LOG_ERR("[%s:%u] error: \"%s\", code: %d", m_url.host(), m_url.port(), message, error["code"].GetInt()); + else if (!isQuiet()) { + LOG_ERR("[%s] error: \"%s\", code: %d", m_pool.url(), message, error["code"].GetInt()); } - if (id == 1 || isCriticalError(message)) { + if (isCriticalError(message)) { close(); } @@ -560,8 +624,8 @@ void Client::parseResponse(int64_t id, const rapidjson::Value &result, const rap if (id == 1) { int code = -1; if (!parseLogin(result, &code)) { - if (!m_quiet) { - LOG_ERR("[%s:%u] login error code: %d", m_url.host(), m_url.port(), code); + if (!isQuiet()) { + LOG_ERR("[%s] login error code: %d", m_pool.url(), code); } close(); @@ -592,18 +656,13 @@ void Client::ping() void Client::reconnect() { if (!m_listener) { - delete this; + m_storage.remove(m_key); return; } setState(ConnectingState); - -# ifndef XMRIG_PROXY_PROJECT - if (m_url.isKeepAlive()) { - uv_timer_stop(&m_keepAliveTimer); - } -# endif + m_keepAlive = 0; if (m_failures == -1) { return m_listener->onClose(this, -1); @@ -618,7 +677,7 @@ void Client::reconnect() void Client::setState(SocketState state) { - LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state); + LOG_DEBUG("[%s] state: %d", m_pool.url(), state); if (m_state == state) { return; @@ -632,13 +691,9 @@ void Client::startTimeout() { m_expire = 0; -# ifndef XMRIG_PROXY_PROJECT - if (!m_url.isKeepAlive()) { - return; + if (m_pool.keepAlive()) { + m_keepAlive = uv_now(uv_default_loop()) + (m_pool.keepAlive() * 1000); } - - uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); -# endif } @@ -669,12 +724,13 @@ void Client::onConnect(uv_connect_t *req, int status) { auto client = getClient(req->data); if (!client) { + delete req; return; } if (status < 0) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); + if (!client->isQuiet()) { + LOG_ERR("[%s] connect error: \"%s\"", client->m_pool.url(), uv_strerror(status)); } delete req; @@ -701,8 +757,8 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) } if (nread < 0) { - if (nread != UV_EOF && !client->m_quiet) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread)); + if (nread != UV_EOF && !client->isQuiet()) { + LOG_ERR("[%s] read error: \"%s\"", client->m_pool.url(), uv_strerror((int) nread)); } client->close(); @@ -714,6 +770,11 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) return; } + assert(client->m_listener != nullptr); + if (!client->m_listener) { + return client->reconnect(); + } + client->m_recvBufPos += nread; char* end; @@ -750,9 +811,14 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) return; } + assert(client->m_listener != nullptr); + if (!client->m_listener) { + return client->reconnect(); + } + if (status < 0) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); + if (!client->isQuiet()) { + LOG_ERR("[%s] DNS error: \"%s\"", client->m_pool.url(), uv_strerror(status)); } return client->reconnect(); @@ -775,8 +841,8 @@ void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) } if (ipv4.empty() && ipv6.empty()) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", client->m_url.host(), client->m_url.port()); + if (!client->isQuiet()) { + LOG_ERR("[%s] DNS error: \"No IPv4 (A) or IPv6 (AAAA) records found\"", client->m_pool.url()); } uv_freeaddrinfo(res); diff --git a/src/net/Client.h b/src/common/net/Client.h similarity index 81% rename from src/net/Client.h rename to src/common/net/Client.h index fff7a156..27273092 100644 --- a/src/net/Client.h +++ b/src/common/net/Client.h @@ -30,10 +30,11 @@ #include -#include "net/Id.h" -#include "net/Job.h" -#include "net/SubmitResult.h" -#include "net/Url.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" @@ -53,36 +54,42 @@ public: }; constexpr static int kResponseTimeout = 20 * 1000; - constexpr static int kKeepAliveTimeout = 60 * 1000; Client(int id, const char *agent, IClientListener *listener); + ~Client(); bool disconnect(); int64_t submit(const JobResult &result); void connect(); - void connect(const Url *url); + void connect(const Pool &pool); void deleteLater(); - void setUrl(const Url *url); + 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_url.host(); } + 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_url.port(); } + inline uint16_t port() const { return m_pool.port(); } 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: - ~Client(); + enum Extensions { + NicehashExt = 1, + AlgoExt = 2 + }; bool close(); bool isCriticalError(const char *message); bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); + 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); @@ -97,13 +104,15 @@ private: 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 static_cast(data); } + static inline Client *getClient(void *data) { return m_storage.get(data); } addrinfo m_hints; bool m_ipv6; @@ -114,26 +123,28 @@ private: char m_sendBuf[768]; 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; - static int64_t m_sequence; std::map m_results; uint64_t m_expire; uint64_t m_jobs; - Url m_url; + 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; -# ifndef XMRIG_PROXY_PROJECT - uv_timer_t m_keepAliveTimer; -# endif + static int64_t m_sequence; + static xmrig::Storage m_storage; }; diff --git a/src/net/Id.h b/src/common/net/Id.h similarity index 100% rename from src/net/Id.h rename to src/common/net/Id.h diff --git a/src/net/Job.cpp b/src/common/net/Job.cpp similarity index 78% rename from src/net/Job.cpp rename to src/common/net/Job.cpp index 7d137fac..81c3b8f8 100644 --- a/src/net/Job.cpp +++ b/src/common/net/Job.cpp @@ -23,10 +23,11 @@ */ +#include #include -#include "net/Job.h" +#include "common/net/Job.h" static inline unsigned char hf_hex2bin(char c, bool &err) @@ -58,11 +59,8 @@ static inline char hf_bin2hex(unsigned char c) Job::Job() : m_nicehash(false), - m_coin(), - m_algo(xmrig::ALGO_CRYPTONIGHT), m_poolId(-2), m_threadId(-1), - m_variant(xmrig::VARIANT_AUTO), m_size(0), m_diff(0), m_target(0), @@ -71,17 +69,16 @@ Job::Job() : } -Job::Job(int poolId, bool nicehash, int algo, int variant) : +Job::Job(int poolId, bool nicehash, xmrig::Algorithm algorithm, const xmrig::Id &clientId) : m_nicehash(nicehash), - m_coin(), - m_algo(algo), m_poolId(poolId), m_threadId(-1), - m_variant(variant), m_size(0), m_diff(0), m_target(0), - m_blob() + m_blob(), + m_algorithm(algorithm), + m_clientId(clientId) { } @@ -115,6 +112,11 @@ bool Job::setBlob(const char *blob) m_nicehash = true; } +# ifdef XMRIG_PROXY_PROJECT + memset(m_rawBlob, 0, sizeof(m_rawBlob)); + memcpy(m_rawBlob, blob, m_size * 2); +# endif + return true; } @@ -151,35 +153,35 @@ bool Job::setTarget(const char *target) 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::setCoin(const char *coin) +xmrig::Variant Job::variant() const { - if (!coin || strlen(coin) > 4) { - memset(m_coin, 0, sizeof(m_coin)); - return; + if (m_algorithm.algo() == xmrig::CRYPTONIGHT_HEAVY) { + return xmrig::VARIANT_0; } - strncpy(m_coin, coin, sizeof(m_coin)); - m_algo = strcmp(m_coin, "AEON") == 0 ? xmrig::ALGO_CRYPTONIGHT_LITE : xmrig::ALGO_CRYPTONIGHT; -} - - -void Job::setVariant(int variant) -{ - switch (variant) { - case xmrig::VARIANT_AUTO: - case xmrig::VARIANT_NONE: - case xmrig::VARIANT_V1: - m_variant = variant; - break; - - default: - break; + if (m_algorithm.variant() == xmrig::VARIANT_XTL && m_blob[0] < 4) { + return xmrig::VARIANT_1; } + + if (m_algorithm.variant() == xmrig::VARIANT_AUTO) { + if (m_algorithm.algo() == xmrig::CRYPTONIGHT) { + return xmrig::VARIANT_1; + } + + return (m_blob[0] > 6 ? xmrig::VARIANT_1 : xmrig::VARIANT_0); + } + + return m_algorithm.variant(); } @@ -206,6 +208,17 @@ void Job::toHex(const unsigned char* in, unsigned int len, char* out) } +#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; diff --git a/src/net/Job.h b/src/common/net/Job.h similarity index 50% rename from src/net/Job.h rename to src/common/net/Job.h index b8b9d6bc..049eb7d4 100644 --- a/src/net/Job.h +++ b/src/common/net/Job.h @@ -30,60 +30,74 @@ #include -#include "net/Id.h" -#include "xmrig.h" +#include "common/crypto/Algorithm.h" +#include "common/net/Id.h" class Job { public: Job(); - Job(int poolId, bool nicehash, int algo, int variant); + Job(int poolId, bool nicehash, xmrig::Algorithm algorithm, const xmrig::Id &clientId); ~Job(); bool setBlob(const char *blob); bool setTarget(const char *target); - void setCoin(const char *coin); - void setVariant(int variant); + xmrig::Variant variant() const; - 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 char *coin() const { return m_coin; } - inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } - inline const uint8_t *blob() const { return m_blob; } - inline const xmrig::Id &id() const { return m_id; } - inline int poolId() const { return m_poolId; } - inline int threadId() const { return m_threadId; } - inline int variant() const { return (m_variant == xmrig::VARIANT_AUTO ? (m_blob[0] > 6 ? 1 : 0) : m_variant); } - inline size_t size() const { return m_size; } - inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } - inline uint32_t diff() const { return (uint32_t) m_diff; } - inline uint64_t target() const { return m_target; } - inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } - inline void setPoolId(int poolId) { m_poolId = poolId; } - inline void setThreadId(int threadId) { m_threadId = threadId; } + 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 xmrig::Algorithm &algorithm() { return m_algorithm; } + +# 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: bool m_nicehash; - char m_coin[5]; - int m_algo; int m_poolId; int m_threadId; - int m_variant; 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 /* __JOB_H__ */ diff --git a/src/common/net/Pool.cpp b/src/common/net/Pool.cpp new file mode 100644 index 00000000..06622d28 --- /dev/null +++ b/src/common/net/Pool.cpp @@ -0,0 +1,307 @@ +/* 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 "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_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_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) : + m_nicehash(nicehash), + 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 +{ + for (const auto &a : m_algorithms) { + if (algorithm == a) { + return true; + } + } + + return false; +} + + +bool Pool::isEqual(const Pool &other) const +{ + return (m_nicehash == other.m_nicehash + && m_keepAlive == other.m_keepAlive + && m_port == other.m_port + && m_algorithm == other.m_algorithm + && 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)) { + 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: + obj.AddMember("variant", m_algorithm.variant(), allocator); + break; + + default: + obj.AddMember("variant", StringRef(m_algorithm.variantName()), allocator); + break; + } + + return obj; +} + + +void Pool::adjust(xmrig::Algo algorithm) +{ + if (!isValid()) { + return; + } + + if (!m_algorithm.isValid()) { + m_algorithm.setAlgo(algorithm); + + if (m_algorithm.variant() == xmrig::VARIANT_AUTO) { + if (algorithm == xmrig::CRYPTONIGHT) { + m_algorithm.setVariant(xmrig::VARIANT_1); + } + } + } + + if (strstr(m_host.data(), ".nicehash.com")) { + m_keepAlive = false; + m_nicehash = true; + + if (strstr(m_host.data(), "cryptonightv7.")) { + m_algorithm.setVariant(xmrig::VARIANT_1); + } + } + + if (strstr(m_host.data(), ".minergate.com")) { + m_keepAlive = false; + m_algorithm.setVariant(xmrig::VARIANT_1); + } + + m_algorithms.push_back(m_algorithm); + +# ifndef XMRIG_PROXY_PROJECT + if (m_algorithm.algo() != xmrig::CRYPTONIGHT_HEAVY) { + addVariant(xmrig::VARIANT_1); + addVariant(xmrig::VARIANT_0); + addVariant(xmrig::VARIANT_XTL); + addVariant(xmrig::VARIANT_IPBC); + addVariant(xmrig::VARIANT_AUTO); + } +# endif +} + + +#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); +} diff --git a/src/common/net/Pool.h b/src/common/net/Pool.h new file mode 100644 index 00000000..ad015bf2 --- /dev/null +++ b/src/common/net/Pool.h @@ -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 . + */ + +#ifndef __POOL_H__ +#define __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 + ); + + inline bool isNicehash() const { return m_nicehash; } + inline bool isValid() const { return !m_host.isNull() && m_port > 0; } + 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 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 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(xmrig::Algo algorithm); + +# ifdef APP_DEBUG + void print() const; +# endif + +private: + bool parseIPv6(const char *addr); + void addVariant(xmrig::Variant variant); + + bool m_nicehash; + int m_keepAlive; + uint16_t m_port; + xmrig::Algorithm m_algorithm; + xmrig::Algorithms m_algorithms; + 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 /* __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/net/SubmitResult.cpp b/src/common/net/SubmitResult.cpp similarity index 82% rename from src/net/SubmitResult.cpp rename to src/common/net/SubmitResult.cpp index 2e81017c..251b2bf1 100644 --- a/src/net/SubmitResult.cpp +++ b/src/common/net/SubmitResult.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,10 +25,11 @@ #include -#include "net/SubmitResult.h" +#include "common/net/SubmitResult.h" -SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff) : +SubmitResult::SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff, int64_t reqId) : + reqId(reqId), seq(seq), diff(diff), actualDiff(actualDiff), diff --git a/src/net/SubmitResult.h b/src/common/net/SubmitResult.h similarity index 80% rename from src/net/SubmitResult.h rename to src/common/net/SubmitResult.h index 8eddef89..e812cbf8 100644 --- a/src/net/SubmitResult.h +++ b/src/common/net/SubmitResult.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 @@ -31,11 +31,12 @@ class SubmitResult { public: - inline SubmitResult() : seq(0), diff(0), actualDiff(0), elapsed(0), start(0) {} - SubmitResult(int64_t seq, uint32_t diff, uint64_t actualDiff); + 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; diff --git a/src/net/strategies/FailoverStrategy.cpp b/src/common/net/strategies/FailoverStrategy.cpp similarity index 92% rename from src/net/strategies/FailoverStrategy.cpp rename to src/common/net/strategies/FailoverStrategy.cpp index dbfeb311..295b4335 100644 --- a/src/net/strategies/FailoverStrategy.cpp +++ b/src/common/net/strategies/FailoverStrategy.cpp @@ -22,13 +22,13 @@ */ +#include "common/net/Client.h" +#include "common/net/strategies/FailoverStrategy.h" +#include "common/Platform.h" #include "interfaces/IStrategyListener.h" -#include "net/Client.h" -#include "net/strategies/FailoverStrategy.h" -#include "Platform.h" -FailoverStrategy::FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet) : +FailoverStrategy::FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet) : m_quiet(quiet), m_retries(retries), m_retryPause(retryPause), @@ -36,7 +36,7 @@ FailoverStrategy::FailoverStrategy(const std::vector &urls, int retryPause m_index(0), m_listener(listener) { - for (const Url *url : urls) { + for (const Pool &url : urls) { add(url); } } @@ -153,10 +153,11 @@ void FailoverStrategy::onResultAccepted(Client *client, const SubmitResult &resu } -void FailoverStrategy::add(const Url *url) +void FailoverStrategy::add(const Pool &pool) { Client *client = new Client((int) m_pools.size(), Platform::userAgent(), this); - client->setUrl(url); + client->setPool(pool); + client->setRetries(m_retries); client->setRetryPause(m_retryPause * 1000); client->setQuiet(m_quiet); diff --git a/src/net/strategies/FailoverStrategy.h b/src/common/net/strategies/FailoverStrategy.h similarity index 94% rename from src/net/strategies/FailoverStrategy.h rename to src/common/net/strategies/FailoverStrategy.h index 8ad767ca..f86b366a 100644 --- a/src/net/strategies/FailoverStrategy.h +++ b/src/common/net/strategies/FailoverStrategy.h @@ -28,6 +28,7 @@ #include +#include "common/net/Pool.h" #include "interfaces/IClientListener.h" #include "interfaces/IStrategy.h" @@ -40,7 +41,7 @@ class Url; class FailoverStrategy : public IStrategy, public IClientListener { public: - FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); + FailoverStrategy(const std::vector &urls, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); ~FailoverStrategy(); public: @@ -59,7 +60,7 @@ protected: void onResultAccepted(Client *client, const SubmitResult &result, const char *error) override; private: - void add(const Url *url); + void add(const Pool &pool); const bool m_quiet; const int m_retries; diff --git a/src/net/strategies/SinglePoolStrategy.cpp b/src/common/net/strategies/SinglePoolStrategy.cpp similarity index 89% rename from src/net/strategies/SinglePoolStrategy.cpp rename to src/common/net/strategies/SinglePoolStrategy.cpp index fc7f209e..21ce7b34 100644 --- a/src/net/strategies/SinglePoolStrategy.cpp +++ b/src/common/net/strategies/SinglePoolStrategy.cpp @@ -22,18 +22,19 @@ */ +#include "common/net/Client.h" +#include "common/net/strategies/SinglePoolStrategy.h" +#include "common/Platform.h" #include "interfaces/IStrategyListener.h" -#include "net/Client.h" -#include "net/strategies/SinglePoolStrategy.h" -#include "Platform.h" -SinglePoolStrategy::SinglePoolStrategy(const Url *url, int retryPause, IStrategyListener *listener, bool quiet) : +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->setUrl(url); + m_client->setPool(pool); + m_client->setRetries(retries); m_client->setRetryPause(retryPause * 1000); m_client->setQuiet(quiet); } diff --git a/src/net/strategies/SinglePoolStrategy.h b/src/common/net/strategies/SinglePoolStrategy.h similarity index 94% rename from src/net/strategies/SinglePoolStrategy.h rename to src/common/net/strategies/SinglePoolStrategy.h index d5682cf7..41d90e34 100644 --- a/src/net/strategies/SinglePoolStrategy.h +++ b/src/common/net/strategies/SinglePoolStrategy.h @@ -37,7 +37,7 @@ class Url; class SinglePoolStrategy : public IStrategy, public IClientListener { public: - SinglePoolStrategy(const Url *url, int retryPause, IStrategyListener *listener, bool quiet = false); + SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false); ~SinglePoolStrategy(); public: diff --git a/src/common/utils/c_str.h b/src/common/utils/c_str.h new file mode 100644 index 00000000..3cc4d326 --- /dev/null +++ b/src/common/utils/c_str.h @@ -0,0 +1,96 @@ +/* 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 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/xmrig.h b/src/common/xmrig.h new file mode 100644 index 00000000..a6fda9fc --- /dev/null +++ b/src/common/xmrig.h @@ -0,0 +1,79 @@ +/* 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_H__ +#define __XMRIG_H__ + + +namespace xmrig +{ + + +enum Algo { + INVALID_ALGO = -1, + CRYPTONIGHT, /* CryptoNight (Monero) */ + CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */ + CRYPTONIGHT_HEAVY /* CryptoNight-Heavy (SUMO) */ +}; + + +//--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_IPBC = 2, // CryptoNight Lite variant 1 with XOR (IPBC only) + VARIANT_XTL = 3 // CryptoNight variant 1 (Stellite only) +}; + + +enum AesMode { + AES_AUTO, + AES_HW, + AES_SOFT +}; + + +} /* namespace xmrig */ + + +#endif /* __XMRIG_H__ */ diff --git a/src/config.json b/src/config.json index 858435d2..b2dad4c9 100644 --- a/src/config.json +++ b/src/config.json @@ -1,32 +1,38 @@ { - "algo": "cryptonight", // cryptonight (default) or cryptonight-lite - "av": 0, // algorithm variation, 0 auto select - "background": false, // true to run the miner in the background - "colors": true, // false to disable colored output - "cpu-affinity": null, // set process affinity to CPU core(s), mask "0x3" for cores 0 and 1 - "cpu-priority": null, // set process priority (0 idle, 2 normal to 5 highest) - "donate-level": 5, // donate level, mininum 1% - "log-file": null, // log all output to a file, example: "c:/some/path/xmrig.log" - "max-cpu-usage": 75, // maximum CPU usage for automatic mode, usually limiting factor is CPU cache not this option. - "print-time": 60, // print hashrate report every N seconds - "retries": 5, // number of times to retry before switch to backup server - "retry-pause": 5, // time to pause between retries - "safe": false, // true to safe adjust threads and av settings for current CPU - "syslog": false, // use system log for output messages - "threads": null, // number of miner threads + "algo": "cryptonight", + "api": { + "port": 0, + "access-token": null, + "worker-id": null, + "ipv6": false, + "restricted": true + }, + "av": 0, + "background": false, + "colors": true, + "cpu-affinity": null, + "cpu-priority": null, + "donate-level": 5, + "huge-pages": true, + "hw-aes": null, + "log-file": null, + "max-cpu-usage": 75, "pools": [ { - "url": "failover.xmrig.com:443", // URL of mining server - "user": "YOUR_WALLET", // username for mining server - "pass": "x", // password for mining server - "keepalive": true, // send keepalived for prevent timeout (need pool support) - "nicehash": false, // enable nicehash/xmrig-proxy support - "variant": -1 // algorithm PoW variant + "url": "proxy.fee.xmrig.com:9999", + "user": "YOUR_WALLET", + "pass": "x", + "rig-id": null, + "nicehash": false, + "keepalive": false, + "variant": 1 } ], - "api": { - "port": 0, // port for the miner API https://github.com/xmrig/xmrig/wiki/API - "access-token": null, // access token for API - "worker-id": null // custom worker-id for API - } + "print-time": 60, + "retries": 5, + "retry-pause": 5, + "safe": false, + "threads": null, + "user-agent": null, + "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..4c283164 --- /dev/null +++ b/src/core/Config.cpp @@ -0,0 +1,371 @@ +/* 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 "core/Config.h" +#include "core/ConfigCreator.h" +#include "Cpu.h" +#include "crypto/CryptoNight_constants.h" +#include "rapidjson/document.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/prettywriter.h" +#include "workers/CpuThread.h" + + +static char affinity_tmp[20] = { 0 }; + + +xmrig::Config::Config() : xmrig::CommonConfig(), + m_aesMode(AES_AUTO), + m_algoVariant(AV_AUTO), + m_dryRun(false), + m_hugePages(true), + m_safe(false), + m_maxCpuUsage(75), + m_priority(-1) +{ +} + + +xmrig::Config::~Config() +{ +} + + +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("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("av", algoVariant(), allocator); + doc.AddMember("background", isBackground(), allocator); + doc.AddMember("colors", isColors(), allocator); + + if (affinity() != -1L) { + snprintf(affinity_tmp, sizeof(affinity_tmp) - 1, "0x%" PRIX64, affinity()); + doc.AddMember("cpu-affinity", StringRef(affinity_tmp), allocator); + } + else { + doc.AddMember("cpu-affinity", kNullType, allocator); + } + + doc.AddMember("cpu-priority", priority() != -1 ? Value(priority()) : Value(kNullType), allocator); + doc.AddMember("donate-level", donateLevel(), allocator); + doc.AddMember("huge-pages", isHugePages(), allocator); + doc.AddMember("hw-aes", m_aesMode == AES_AUTO ? Value(kNullType) : Value(m_aesMode == AES_HW), allocator); + doc.AddMember("log-file", logFile() ? Value(StringRef(logFile())).Move() : Value(kNullType).Move(), allocator); + doc.AddMember("max-cpu-usage", m_maxCpuUsage, 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); + doc.AddMember("safe", m_safe, allocator); + + if (threadsMode() == Advanced) { + Value threads(kArrayType); + + for (const IThread *thread : m_threads.list) { + threads.PushBack(thread->toConfig(doc), doc.GetAllocator()); + } + + doc.AddMember("threads", threads, allocator); + } + else { + doc.AddMember("threads", threadsMode() == Automatic ? Value(kNullType) : Value(threadsCount()), allocator); + } + + doc.AddMember("user-agent", userAgent() ? Value(StringRef(userAgent())).Move() : Value(kNullType).Move(), allocator); + +# ifdef HAVE_SYSLOG_H + doc.AddMember("syslog", isSyslog(), allocator); +# endif + + 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.cpu.empty()) { + m_threads.mode = Advanced; + const bool softAES = (m_aesMode == AES_AUTO ? (Cpu::hasAES() ? AES_HW : AES_SOFT) : m_aesMode) == AES_SOFT; + + for (size_t i = 0; i < m_threads.cpu.size(); ++i) { + m_threads.list.push_back(CpuThread::createFromData(i, m_algorithm.algo(), m_threads.cpu[i], m_priority, softAES)); + } + + return true; + } + + const AlgoVariant av = getAlgoVariant(); + m_threads.mode = m_threads.count ? Simple : Automatic; + + const size_t size = CpuThread::multiway(av) * cn_select_memory(m_algorithm.algo()) / 1024; + + if (!m_threads.count) { + m_threads.count = Cpu::optimalThreadsCount(size, m_maxCpuUsage); + } + else if (m_safe) { + const size_t count = Cpu::optimalThreadsCount(size, m_maxCpuUsage); + if (m_threads.count > count) { + m_threads.count = count; + } + } + + for (size_t i = 0; i < m_threads.count; ++i) { + m_threads.list.push_back(CpuThread::createFromAV(i, m_algorithm.algo(), av, m_threads.mask, m_priority)); + } + + return true; +} + + +bool xmrig::Config::parseBoolean(int key, bool enable) +{ + if (!CommonConfig::parseBoolean(key, enable)) { + return false; + } + + switch (key) { + case IConfig::SafeKey: /* --safe */ + m_safe = enable; + break; + + case IConfig::HugePagesKey: /* --no-huge-pages */ + m_hugePages = enable; + break; + + case IConfig::DryRunKey: /* --dry-run */ + m_dryRun = enable; + break; + + case IConfig::HardwareAESKey: /* hw-aes config only */ + m_aesMode = enable ? AES_HW : AES_SOFT; + break; + + default: + break; + } + + return true; +} + + +bool xmrig::Config::parseString(int key, const char *arg) +{ + if (!CommonConfig::parseString(key, arg)) { + return false; + } + + switch (key) { + case xmrig::IConfig::AVKey: /* --av */ + case xmrig::IConfig::MaxCPUUsageKey: /* --max-cpu-usage */ + case xmrig::IConfig::CPUPriorityKey: /* --cpu-priority */ + return parseUint64(key, strtol(arg, nullptr, 10)); + + case xmrig::IConfig::SafeKey: /* --safe */ + case xmrig::IConfig::DryRunKey: /* --dry-run */ + return parseBoolean(key, true); + + case xmrig::IConfig::HugePagesKey: /* --no-huge-pages */ + return parseBoolean(key, false); + + case xmrig::IConfig::ThreadsKey: /* --threads */ + if (strncmp(arg, "all", 3) == 0) { + m_threads.count = Cpu::threads(); + return true; + } + + return parseUint64(key, strtol(arg, nullptr, 10)); + + case xmrig::IConfig::CPUAffinityKey: /* --cpu-affinity */ + { + const char *p = strstr(arg, "0x"); + return parseUint64(key, p ? strtoull(p, nullptr, 16) : strtoull(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 xmrig::IConfig::CPUAffinityKey: /* --cpu-affinity */ + if (arg) { + m_threads.mask = arg; + } + break; + + default: + return parseInt(key, static_cast(arg)); + } + + 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("low_power_mode")) { + auto data = CpuThread::parse(value); + + if (data.valid) { + m_threads.cpu.push_back(std::move(data)); + } + } + } + } +} + + +bool xmrig::Config::parseInt(int key, int arg) +{ + switch (key) { + case xmrig::IConfig::ThreadsKey: /* --threads */ + if (arg >= 0 && arg < 1024) { + m_threads.count = arg; + } + break; + + case xmrig::IConfig::AVKey: /* --av */ + if (arg >= AV_AUTO && arg < AV_MAX) { + m_algoVariant = static_cast(arg); + } + break; + + case xmrig::IConfig::MaxCPUUsageKey: /* --max-cpu-usage */ + if (m_maxCpuUsage > 0 && arg <= 100) { + m_maxCpuUsage = arg; + } + break; + + case xmrig::IConfig::CPUPriorityKey: /* --cpu-priority */ + if (arg >= 0 && arg <= 5) { + m_priority = arg; + } + break; + + default: + break; + } + + return true; +} + + +xmrig::AlgoVariant xmrig::Config::getAlgoVariant() const +{ +# ifndef XMRIG_NO_AEON + if (m_algorithm.algo() == xmrig::CRYPTONIGHT_LITE) { + return getAlgoVariantLite(); + } +# endif + + if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { + return Cpu::hasAES() ? AV_SINGLE : AV_SINGLE_SOFT; + } + + if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV_DOUBLE) { + return static_cast(m_algoVariant + 2); + } + + return m_algoVariant; +} + + +#ifndef XMRIG_NO_AEON +xmrig::AlgoVariant xmrig::Config::getAlgoVariantLite() const +{ + if (m_algoVariant <= AV_AUTO || m_algoVariant >= AV_MAX) { + return Cpu::hasAES() ? AV_DOUBLE : AV_DOUBLE_SOFT; + } + + if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV_DOUBLE) { + return static_cast(m_algoVariant + 2); + } + + return m_algoVariant; +} +#endif diff --git a/src/core/Config.h b/src/core/Config.h new file mode 100644 index 00000000..0c6a2173 --- /dev/null +++ b/src/core/Config.h @@ -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 . + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + + +#include +#include + + +#include "common/config/CommonConfig.h" +#include "common/xmrig.h" +#include "rapidjson/fwd.h" +#include "workers/CpuThread.h" + + +class Addr; +class Url; + + +namespace xmrig { + + +class ConfigLoader; +class IThread; +class IWatcherListener; + + +/** + * @brief The Config class + * + * Options with dynamic reload: + * colors + * debug + * verbose + * custom-diff (only for new connections) + * api/worker-id + * pools/ + */ +class Config : public CommonConfig +{ +public: + enum ThreadsMode { + Automatic, + Simple, + Advanced + }; + + + Config(); + ~Config(); + + bool reload(const char *json); + + void getJSON(rapidjson::Document &doc) const override; + + inline AesMode aesMode() const { return m_aesMode; } + inline AlgoVariant algoVariant() const { return m_algoVariant; } + inline bool isDryRun() const { return m_dryRun; } + inline bool isHugePages() const { return m_hugePages; } + inline const std::vector &threads() const { return m_threads.list; } + inline int priority() const { return m_priority; } + inline int threadsCount() const { return m_threads.list.size(); } + inline int64_t affinity() const { return m_threads.mask; } + inline ThreadsMode threadsMode() const { return m_threads.mode; } + + static Config *load(int argc, char **argv, IWatcherListener *listener); + +protected: + 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 parseJSON(const rapidjson::Document &doc) override; + +private: + bool parseInt(int key, int arg); + + AlgoVariant getAlgoVariant() const; +# ifndef XMRIG_NO_AEON + AlgoVariant getAlgoVariantLite() const; +# endif + + + struct Threads + { + inline Threads() : mask(-1L), count(0), mode(Automatic) {} + + int64_t mask; + size_t count; + std::vector cpu; + std::vector list; + ThreadsMode mode; + }; + + + AesMode m_aesMode; + AlgoVariant m_algoVariant; + bool m_dryRun; + bool m_hugePages; + bool m_safe; + int m_maxCpuUsage; + int m_priority; + Threads m_threads; +}; + + +} /* namespace xmrig */ + +#endif /* __CONFIG_H__ */ diff --git a/src/core/ConfigCreator.h b/src/core/ConfigCreator.h new file mode 100644 index 00000000..fcc6c596 --- /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 "core/Config.h" +#include "interfaces/IConfigCreator.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..9704d5e3 --- /dev/null +++ b/src/core/ConfigLoader_platform.h @@ -0,0 +1,187 @@ +/* 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_PLATFORM_H__ +#define __CONFIGLOADER_PLATFORM_H__ + + +#ifdef _MSC_VER +# include "getopt/getopt.h" +#else +# include +#endif + + +#include "version.h" +#include "interfaces/IConfig.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\ + -t, --threads=N number of miner threads\n\ + -v, --av=N algorithm variation, 0 auto select\n\ + -k, --keepalive send keepalived for prevent timeout (need pool support)\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\ + --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ + --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ + --no-huge-pages disable huge pages support\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 +"\ + --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\ + --safe safe adjust threads and av settings for current CPU\n\ + --nicehash enable nicehash/xmrig-proxy support\n\ + --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-ipv6 enable IPv6 support for API\n\ + --api-no-restricted enable full remote access (only if API token set)\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:T:o:u:O:v: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-ipv6", 0, nullptr, xmrig::IConfig::ApiIPv6Key }, + { "api-no-restricted", 0, nullptr, xmrig::IConfig::ApiRestrictedKey }, + { "av", 1, nullptr, xmrig::IConfig::AVKey }, + { "background", 0, nullptr, xmrig::IConfig::BackgroundKey }, + { "config", 1, nullptr, xmrig::IConfig::ConfigKey }, + { "cpu-affinity", 1, nullptr, xmrig::IConfig::CPUAffinityKey }, + { "cpu-priority", 1, nullptr, xmrig::IConfig::CPUPriorityKey }, + { "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 }, + { "max-cpu-usage", 1, nullptr, xmrig::IConfig::MaxCPUUsageKey }, + { "nicehash", 0, nullptr, xmrig::IConfig::NicehashKey }, + { "no-color", 0, nullptr, xmrig::IConfig::ColorKey }, + { "no-huge-pages", 0, nullptr, xmrig::IConfig::HugePagesKey }, + { "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 }, + { "safe", 0, nullptr, xmrig::IConfig::SafeKey }, + { "syslog", 0, nullptr, xmrig::IConfig::SyslogKey }, + { "threads", 1, nullptr, xmrig::IConfig::ThreadsKey }, + { "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 }, + { "version", 0, nullptr, xmrig::IConfig::VersionKey }, + { 0, 0, 0, 0 } +}; + + +static struct option const config_options[] = { + { "algo", 1, nullptr, xmrig::IConfig::AlgorithmKey }, + { "av", 1, nullptr, xmrig::IConfig::AVKey }, + { "background", 0, nullptr, xmrig::IConfig::BackgroundKey }, + { "colors", 0, nullptr, xmrig::IConfig::ColorKey }, + { "cpu-affinity", 1, nullptr, xmrig::IConfig::CPUAffinityKey }, + { "cpu-priority", 1, nullptr, xmrig::IConfig::CPUPriorityKey }, + { "donate-level", 1, nullptr, xmrig::IConfig::DonateLevelKey }, + { "dry-run", 0, nullptr, xmrig::IConfig::DryRunKey }, + { "huge-pages", 0, nullptr, xmrig::IConfig::HugePagesKey }, + { "log-file", 1, nullptr, xmrig::IConfig::LogFileKey }, + { "max-cpu-usage", 1, nullptr, xmrig::IConfig::MaxCPUUsageKey }, + { "print-time", 1, nullptr, xmrig::IConfig::PrintTimeKey }, + { "retries", 1, nullptr, xmrig::IConfig::RetriesKey }, + { "retry-pause", 1, nullptr, xmrig::IConfig::RetryPauseKey }, + { "safe", 0, nullptr, xmrig::IConfig::SafeKey }, + { "syslog", 0, nullptr, xmrig::IConfig::SyslogKey }, + { "threads", 1, nullptr, xmrig::IConfig::ThreadsKey }, + { "user-agent", 1, nullptr, xmrig::IConfig::UserAgentKey }, + { "hw-aes", 0, nullptr, xmrig::IConfig::HardwareAESKey }, + { 0, 0, 0, 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 }, + { 0, 0, 0, 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 }, + { 0, 0, 0, 0 } +}; + + +} /* namespace xmrig */ + +#endif /* __CONFIGLOADER_PLATFORM_H__ */ diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp new file mode 100644 index 00000000..b1e03f32 --- /dev/null +++ b/src/core/Controller.cpp @@ -0,0 +1,151 @@ +/* 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/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 "Cpu.h" +#include "interfaces/IControllerListener.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()); + Platform::setProcessPriority(d_ptr->config->priority()); + + if (!config()->isBackground()) { + Log::add(new ConsoleLog(this)); + } + + if (config()->logFile()) { + Log::add(new FileLog(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..25f91843 --- /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 __CONTROLLER_H__ +#define __CONTROLLER_H__ + + +#include "interfaces/IWatcherListener.h" + + +class Network; +class StatsData; + + +namespace xmrig { + + +class Config; +class ControllerPrivate; +class IControllerListener; + + +class Controller : public IWatcherListener +{ +public: + Controller(); + ~Controller(); + + 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 /* __CONTROLLER_H__ */ diff --git a/src/crypto/CryptoNight.cpp b/src/crypto/CryptoNight.cpp deleted file mode 100644 index b605bfb8..00000000 --- a/src/crypto/CryptoNight.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* 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 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 "crypto/CryptoNight.h" - - -#if defined(XMRIG_ARM) -# include "crypto/CryptoNight_arm.h" -#else -# include "crypto/CryptoNight_x86.h" -#endif - -#include "crypto/CryptoNight_test.h" -#include "net/Job.h" -#include "net/JobResult.h" -#include "Options.h" -#include "xmrig.h" - - -void (*cryptonight_hash_ctx)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) = nullptr; - - -#define CRYPTONIGHT_HASH(NAME, ITERATIONS, MEM, MASK, SOFT_AES) \ - switch (variant) { \ - case xmrig::VARIANT_V1: \ - return cryptonight_##NAME##_hash(input, size, output, ctx); \ - \ - case xmrig::VARIANT_NONE: \ - return cryptonight_##NAME##_hash(input, size, output, ctx); \ - \ - default: \ - break; \ - } - - -static void cryptonight_av1_aesni(const uint8_t *input, size_t size, uint8_t *output, struct cryptonight_ctx *ctx, int variant) { -# if !defined(XMRIG_ARMv7) - CRYPTONIGHT_HASH(single, MONERO_ITER, MONERO_MEMORY, MONERO_MASK, false) -# endif -} - - -static void cryptonight_av2_aesni_double(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { -# if !defined(XMRIG_ARMv7) - CRYPTONIGHT_HASH(double, MONERO_ITER, MONERO_MEMORY, MONERO_MASK, false) -# endif -} - - -static void cryptonight_av3_softaes(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { - CRYPTONIGHT_HASH(single, MONERO_ITER, MONERO_MEMORY, MONERO_MASK, true) -} - - -static void cryptonight_av4_softaes_double(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { - CRYPTONIGHT_HASH(double, MONERO_ITER, MONERO_MEMORY, MONERO_MASK, true) -} - - -#ifndef XMRIG_NO_AEON -static void cryptonight_lite_av1_aesni(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { -# if !defined(XMRIG_ARMv7) - CRYPTONIGHT_HASH(single, AEON_ITER, AEON_MEMORY, AEON_MASK, false) -# endif -} - - -static void cryptonight_lite_av2_aesni_double(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { -# if !defined(XMRIG_ARMv7) - CRYPTONIGHT_HASH(double, AEON_ITER, AEON_MEMORY, AEON_MASK, false) -# endif -} - - -static void cryptonight_lite_av3_softaes(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { - CRYPTONIGHT_HASH(single, AEON_ITER, AEON_MEMORY, AEON_MASK, true) -} - - -static void cryptonight_lite_av4_softaes_double(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) { - CRYPTONIGHT_HASH(double, AEON_ITER, AEON_MEMORY, AEON_MASK, true) -} - -void (*cryptonight_variations[8])(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) = { - cryptonight_av1_aesni, - cryptonight_av2_aesni_double, - cryptonight_av3_softaes, - cryptonight_av4_softaes_double, - cryptonight_lite_av1_aesni, - cryptonight_lite_av2_aesni_double, - cryptonight_lite_av3_softaes, - cryptonight_lite_av4_softaes_double - }; -#else -void (*cryptonight_variations[4])(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) = { - cryptonight_av1_aesni, - cryptonight_av2_aesni_double, - cryptonight_av3_softaes, - cryptonight_av4_softaes_double - }; -#endif - - -bool CryptoNight::hash(const Job &job, JobResult &result, cryptonight_ctx *ctx) -{ - cryptonight_hash_ctx(job.blob(), job.size(), result.result, ctx, job.variant()); - - return *reinterpret_cast(result.result + 24) < job.target(); -} - - -bool CryptoNight::init(int algo, int variant) -{ - if (variant < 1 || variant > 4) { - return false; - } - -# ifndef XMRIG_NO_AEON - const int index = algo == xmrig::ALGO_CRYPTONIGHT_LITE ? (variant + 3) : (variant - 1); -# else - const int index = variant - 1; -# endif - - cryptonight_hash_ctx = cryptonight_variations[index]; - - return selfTest(algo); -} - - -void CryptoNight::hash(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant) -{ - cryptonight_hash_ctx(input, size, output, ctx, variant); -} - - -bool CryptoNight::selfTest(int algo) { - if (cryptonight_hash_ctx == nullptr) { - return false; - } - - uint8_t output[64]; - - struct cryptonight_ctx *ctx = static_cast(_mm_malloc(sizeof(cryptonight_ctx), 16)); - ctx->memory = static_cast(_mm_malloc(MONERO_MEMORY * 2, 16)); - - cryptonight_hash_ctx(test_input, 76, output, ctx, 0); - - const bool doubleHash = Options::i()->doubleHash(); - -# ifndef XMRIG_NO_AEON - bool rc = memcmp(output, algo == xmrig::ALGO_CRYPTONIGHT_LITE ? test_output_v0_lite : test_output_v0, (doubleHash ? 64 : 32)) == 0; -# else - bool rc = memcmp(output, test_output_v0, (doubleHash ? 64 : 32)) == 0; -# endif - - if (rc) { - cryptonight_hash_ctx(test_input, 76, output, ctx, 1); - -# ifndef XMRIG_NO_AEON - rc = memcmp(output, algo == xmrig::ALGO_CRYPTONIGHT_LITE ? test_output_v1_lite : test_output_v1, (doubleHash ? 64 : 32)) == 0; -# else - rc = memcmp(output, test_output_v1, (doubleHash ? 64 : 32)) == 0; -# endif - } - - _mm_free(ctx->memory); - _mm_free(ctx); - - return rc; -} diff --git a/src/crypto/CryptoNight.h b/src/crypto/CryptoNight.h index 13e9c8e8..e8e86dc4 100644 --- a/src/crypto/CryptoNight.h +++ b/src/crypto/CryptoNight.h @@ -30,35 +30,10 @@ #include -#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 state1[200]; + alignas(16) uint8_t state[200]; alignas(16) uint8_t* memory; }; -class Job; -class JobResult; - - -class CryptoNight -{ -public: - static bool hash(const Job &job, JobResult &result, cryptonight_ctx *ctx); - static bool init(int algo, int variant); - static void hash(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx, int variant); - -private: - static bool selfTest(int algo); -}; - #endif /* __CRYPTONIGHT_H__ */ diff --git a/src/crypto/CryptoNight_arm.h b/src/crypto/CryptoNight_arm.h index 18408536..746de79c 100644 --- a/src/crypto/CryptoNight_arm.h +++ b/src/crypto/CryptoNight_arm.h @@ -27,14 +27,9 @@ #define __CRYPTONIGHT_ARM_H__ -#if defined(XMRIG_ARM) && !defined(__clang__) -# include "aligned_malloc.h" -#else -# include -#endif - - +#include "common/utils/mm_malloc.h" #include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" #include "crypto/CryptoNight_monero.h" #include "crypto/soft_aes.h" @@ -78,6 +73,19 @@ static inline __attribute__((always_inline)) __m128i _mm_set_epi64x(const uint64 } +#ifdef XMRIG_ARMv8 +static inline __attribute__((always_inline)) __m128i _mm_aesenc_si128(__m128i v, __m128i rkey) +{ + alignas(16) const __m128i zero = { 0 }; + return veorq_u8(vaesmcq_u8(vaeseq_u8(v, zero)), rkey ); +} +#else +static inline __attribute__((always_inline)) __m128i _mm_aesenc_si128(__m128i v, __m128i rkey) +{ +} +#endif + + /* this one was not implemented yet so here it is */ static inline __attribute__((always_inline)) uint64_t _mm_cvtsi128_si64(__m128i a) { @@ -160,19 +168,19 @@ static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, _ *k0 = xout0; *k1 = xout2; - SOFT_AES ? soft_aes_genkey_sub<0x01>(&xout0, &xout2) : soft_aes_genkey_sub<0x01>(&xout0, &xout2); + soft_aes_genkey_sub<0x01>(&xout0, &xout2); *k2 = xout0; *k3 = xout2; - SOFT_AES ? soft_aes_genkey_sub<0x02>(&xout0, &xout2) : soft_aes_genkey_sub<0x02>(&xout0, &xout2); + soft_aes_genkey_sub<0x02>(&xout0, &xout2); *k4 = xout0; *k5 = xout2; - SOFT_AES ? soft_aes_genkey_sub<0x04>(&xout0, &xout2) : soft_aes_genkey_sub<0x04>(&xout0, &xout2); + soft_aes_genkey_sub<0x04>(&xout0, &xout2); *k6 = xout0; *k7 = xout2; - SOFT_AES ? soft_aes_genkey_sub<0x08>(&xout0, &xout2) : soft_aes_genkey_sub<0x08>(&xout0, &xout2); + soft_aes_genkey_sub<0x08>(&xout0, &xout2); *k8 = xout0; *k9 = xout2; } @@ -191,22 +199,34 @@ static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, *x6 = soft_aesenc((uint32_t*)x6, key); *x7 = soft_aesenc((uint32_t*)x7, key); } -# ifndef XMRIG_ARMv7 else { - *x0 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x0), key)); - *x1 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x1), key)); - *x2 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x2), key)); - *x3 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x3), key)); - *x4 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x4), key)); - *x5 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x5), key)); - *x6 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x6), key)); - *x7 = vaesmcq_u8(vaeseq_u8(*((uint8x16_t *) x7), key)); + *x0 = _mm_aesenc_si128(*x0, key); + *x1 = _mm_aesenc_si128(*x1, key); + *x2 = _mm_aesenc_si128(*x2, key); + *x3 = _mm_aesenc_si128(*x3, key); + *x4 = _mm_aesenc_si128(*x4, key); + *x5 = _mm_aesenc_si128(*x5, key); + *x6 = _mm_aesenc_si128(*x6, key); + *x7 = _mm_aesenc_si128(*x7, key); } -# endif } -template +inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3, __m128i& x4, __m128i& x5, __m128i& x6, __m128i& x7) +{ + __m128i tmp0 = x0; + x0 = _mm_xor_si128(x0, x1); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_xor_si128(x2, x3); + x3 = _mm_xor_si128(x3, x4); + x4 = _mm_xor_si128(x4, x5); + x5 = _mm_xor_si128(x5, x6); + x6 = _mm_xor_si128(x6, x7); + x7 = _mm_xor_si128(x7, tmp0); +} + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; @@ -223,11 +243,24 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); - for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { - if (!SOFT_AES) { - aes_round(_mm_setzero_si128(), &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); - } + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + for (size_t i = 0; i < 16; i++) { + aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + mix_and_propagate(xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7); + } + } + + for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -237,20 +270,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); - - if (!SOFT_AES) { - xin0 ^= k9; - xin1 ^= k9; - xin2 ^= k9; - xin3 ^= k9; - xin4 ^= k9; - xin5 ^= k9; - xin6 ^= k9; - xin7 ^= k9; - } - else { - aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); - } + aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); _mm_store_si128(output + i + 0, xin0); _mm_store_si128(output + i + 1, xin1); @@ -264,7 +284,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; @@ -292,10 +312,6 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6); xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7); - if (!SOFT_AES) { - aes_round(_mm_setzero_si128(), &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - } - aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); @@ -305,19 +321,51 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); - if (!SOFT_AES) { - xout0 ^= k9; - xout1 ^= k9; - xout2 ^= k9; - xout3 ^= k9; - xout4 ^= k9; - xout5 ^= k9; - xout6 ^= k9; - xout7 ^= k9; + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } - else { + } + + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); + xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); + xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); + xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3); + xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4); + xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5); + xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6); + xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7); + + aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); + } + + for (size_t i = 0; i < 16; i++) { + aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); } } @@ -332,17 +380,41 @@ 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 void cryptonight_monero_tweak(uint64_t* mem_out, __m128i tmp) { - keccak(input, (int) size, ctx->state0, 200); + mem_out[0] = EXTRACT64(tmp); + + uint64_t vh = vgetq_lane_u64(tmp, 1); + + uint8_t x = vh >> 24; + static const uint16_t table = 0x7531; + const uint8_t index = (((x >> 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 MEM = xmrig::cn_select_memory(); + + if (VARIANT > 0 && size < 43) { + memset(output, 0, 32); + return; + } + + keccak(input, (int) size, ctx[0]->state, 200); VARIANT1_INIT(0); - cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory); + cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); - const uint8_t* l0 = ctx->memory; - uint64_t* h0 = reinterpret_cast(ctx->state0); + const uint8_t* l0 = ctx[0]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); uint64_t al0 = h0[0] ^ h0[4]; uint64_t ah0 = h0[1] ^ h0[5]; @@ -358,13 +430,15 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si } else { cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); -# ifndef XMRIG_ARMv7 - cx = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0); -# endif + cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0)); + } + + if (VARIANT > 0) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + } else { + _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); } - _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); - VARIANT1_1(&l0[idx0 & MASK]); idx0 = EXTRACT64(cx); bx0 = cx; @@ -384,31 +458,49 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si ah0 ^= ch; al0 ^= cl; 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; + idx0 = d ^ q; + } } - cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0); + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); keccakf(h0, 24); - extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } -template -inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx) +template +inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) { - keccak(input, (int) size, ctx->state0, 200); - keccak(input + size, (int) size, ctx->state1, 200); + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + + if (VARIANT > 0 && size < 43) { + memset(output, 0, 64); + return; + } + + keccak(input, (int) size, ctx[0]->state, 200); + keccak(input + size, (int) size, ctx[1]->state, 200); VARIANT1_INIT(0); VARIANT1_INIT(1); - const uint8_t* l0 = ctx->memory; - const uint8_t* l1 = ctx->memory + MEM; - uint64_t* h0 = reinterpret_cast(ctx->state0); - uint64_t* h1 = reinterpret_cast(ctx->state1); + 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); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + 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]; @@ -431,16 +523,17 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si else { cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]); -# ifndef XMRIG_ARMv7 - cx0 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx0, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah0, al0); - cx1 = vreinterpretq_m128i_u8(vaesmcq_u8(vaeseq_u8(cx1, vdupq_n_u8(0)))) ^ _mm_set_epi64x(ah1, al1); -# endif + cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0)); + cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1)); } - _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); - _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); - VARIANT1_1(&l0[idx0 & MASK]); - VARIANT1_1(&l1[idx1 & MASK]); + if (VARIANT > 0) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); + } else { + _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); + _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); + }; idx0 = EXTRACT64(cx0); idx1 = EXTRACT64(cx1); @@ -465,6 +558,15 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si al0 ^= cl; 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; + idx0 = d ^ q; + } + cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; lo = __umul128(idx1, cl, &hi); @@ -480,16 +582,43 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si ah1 ^= ch; al1 ^= cl; 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; + idx1 = d ^ q; + } } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); + cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); keccakf(h0, 24); keccakf(h1, 24); - extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output); - extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, output + 32); + 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); +} + + +template +inline void cryptonight_triple_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +{ +} + + +template +inline void cryptonight_quad_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +{ +} + + +template +inline void cryptonight_penta_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx **__restrict__ ctx) +{ } #endif /* __CRYPTONIGHT_ARM_H__ */ diff --git a/src/crypto/CryptoNight_constants.h b/src/crypto/CryptoNight_constants.h new file mode 100644 index 00000000..7e6627fd --- /dev/null +++ b/src/crypto/CryptoNight_constants.h @@ -0,0 +1,135 @@ +/* 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 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 __CRYPTONIGHT_CONSTANTS_H__ +#define __CRYPTONIGHT_CONSTANTS_H__ + + +#include + + +#include "common/xmrig.h" + + +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 size_t CRYPTONIGHT_LITE_MEMORY = 1 * 1024 * 1024; +constexpr const uint32_t CRYPTONIGHT_LITE_MASK = 0xFFFF0; +constexpr const uint32_t CRYPTONIGHT_LITE_ITER = 0x40000; + +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; + + +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; } + + +inline size_t cn_select_memory(Algo algorithm) +{ + switch(algorithm) + { + case CRYPTONIGHT: + return CRYPTONIGHT_MEMORY; + + case CRYPTONIGHT_LITE: + return CRYPTONIGHT_LITE_MEMORY; + + case CRYPTONIGHT_HEAVY: + return CRYPTONIGHT_HEAVY_MEMORY; + + default: + break; + } + + return 0; +} + + +template inline constexpr uint32_t cn_select_mask() { return 0; } +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; } + + +inline uint32_t cn_select_mask(Algo algorithm) +{ + switch(algorithm) + { + case CRYPTONIGHT: + return CRYPTONIGHT_MASK; + + case CRYPTONIGHT_LITE: + return CRYPTONIGHT_LITE_MASK; + + case CRYPTONIGHT_HEAVY: + return CRYPTONIGHT_HEAVY_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; } + + +inline uint32_t cn_select_iter(Algo algorithm) +{ + switch(algorithm) + { + case CRYPTONIGHT: + return CRYPTONIGHT_ITER; + + case CRYPTONIGHT_LITE: + return CRYPTONIGHT_LITE_ITER; + + case CRYPTONIGHT_HEAVY: + return CRYPTONIGHT_HEAVY_ITER; + + default: + break; + } + + return 0; +} + + +} /* namespace xmrig */ + + +#endif /* __CRYPTONIGHT_CONSTANTS_H__ */ diff --git a/src/crypto/CryptoNight_monero.h b/src/crypto/CryptoNight_monero.h index a667a3b3..ea1622ab 100644 --- a/src/crypto/CryptoNight_monero.h +++ b/src/crypto/CryptoNight_monero.h @@ -32,14 +32,14 @@ uint64_t tweak1_2_##part = 0; \ if (VARIANT > 0) { \ 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); \ + volatile const uint64_t b = *(reinterpret_cast(ctx[part]->state) + 24); \ tweak1_2_##part = a ^ b; \ } #endif diff --git a/src/crypto/CryptoNight_test.h b/src/crypto/CryptoNight_test.h index 0f7feda1..bf6013e8 100644 --- a/src/crypto/CryptoNight_test.h +++ b/src/crypto/CryptoNight_test.h @@ -26,52 +26,137 @@ #define __CRYPTONIGHT_TEST_H__ -const static uint8_t test_input[152] = { +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, - 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 + 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[64] = { +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, - 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 + 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[64] = { - 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, +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 + 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, + 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 +}; + + +// 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 }; #ifndef XMRIG_NO_AEON -const static uint8_t test_output_v0_lite[64] = { +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, - 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 + 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[64] = { +// 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, - 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 + 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 +}; + + +// IPBC +const static uint8_t test_output_ipbc_lite[160] = { + 0xE4, 0x93, 0x8C, 0xAA, 0x59, 0x8D, 0x02, 0x8A, 0xB8, 0x6F, 0x25, 0xD2, 0xB1, 0x23, 0xD0, 0xD5, + 0x33, 0xE3, 0x9F, 0x37, 0xAC, 0xE5, 0xF8, 0xEB, 0x7A, 0xE8, 0x40, 0xEB, 0x5D, 0xB1, 0x35, 0x5F, + 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, + 0x88, 0x45, 0x0B, 0x91, 0x0B, 0x7B, 0xCB, 0x21, 0x3C, 0x3C, 0x09, 0x30, 0x07, 0x71, 0x07, 0xD5, + 0xB8, 0x2D, 0x83, 0x09, 0xAF, 0x7E, 0xB2, 0xA8, 0xAC, 0x25, 0xDC, 0x10, 0xF8, 0x63, 0x6A, 0xBC, + 0x73, 0x01, 0x4E, 0xA8, 0x1C, 0xDA, 0x9A, 0x86, 0x17, 0xEC, 0xA8, 0xFB, 0xAA, 0x23, 0x23, 0x17, + 0xE1, 0x32, 0x68, 0x9C, 0x4C, 0xF4, 0x08, 0xED, 0xB0, 0x15, 0xC3, 0xA9, 0x0F, 0xF0, 0xA2, 0x7E, + 0xD9, 0xE4, 0x23, 0xA7, 0x9E, 0x91, 0xD8, 0x73, 0x94, 0xD6, 0x6C, 0x70, 0x9B, 0x8B, 0x72, 0x92, + 0xA3, 0xA4, 0x0A, 0xE2, 0x3C, 0x0A, 0x34, 0x88, 0xA1, 0x6D, 0xFE, 0x02, 0x44, 0x60, 0x7B, 0x3D +}; +#endif + + +#ifndef XMRIG_NO_SUMO +const static uint8_t test_output_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, + 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 diff --git a/src/crypto/CryptoNight_x86.h b/src/crypto/CryptoNight_x86.h index b7544dcc..66bcf8b5 100644 --- a/src/crypto/CryptoNight_x86.h +++ b/src/crypto/CryptoNight_x86.h @@ -34,14 +34,15 @@ #endif +#include "common/crypto/keccak.h" #include "crypto/CryptoNight.h" +#include "crypto/CryptoNight_constants.h" #include "crypto/CryptoNight_monero.h" #include "crypto/soft_aes.h" extern "C" { -#include "crypto/c_keccak.h" #include "crypto/c_groestl.h" #include "crypto/c_blake256.h" #include "crypto/c_jh.h" @@ -217,7 +218,21 @@ static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, } -template +inline void mix_and_propagate(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3, __m128i& x4, __m128i& x5, __m128i& x6, __m128i& x7) +{ + __m128i tmp0 = x0; + x0 = _mm_xor_si128(x0, x1); + x1 = _mm_xor_si128(x1, x2); + x2 = _mm_xor_si128(x2, x3); + x3 = _mm_xor_si128(x3, x4); + x4 = _mm_xor_si128(x4, x5); + x5 = _mm_xor_si128(x5, x6); + x6 = _mm_xor_si128(x6, x7); + x7 = _mm_xor_si128(x7, tmp0); +} + + +template static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) { __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7; @@ -234,6 +249,23 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) xin6 = _mm_load_si128(input + 10); xin7 = _mm_load_si128(input + 11); + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + for (size_t i = 0; i < 16; i++) { + aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); + + mix_and_propagate(xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7); + } + } + for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7); @@ -258,7 +290,7 @@ static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output) } -template +template static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) { __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7; @@ -296,6 +328,51 @@ static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output) aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); + } + } + + if (ALGO == xmrig::CRYPTONIGHT_HEAVY) { + for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) { + xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0); + xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1); + xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2); + xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3); + xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4); + xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5); + xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6); + xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7); + + aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); + } + + for (size_t i = 0; i < 16; i++) { + aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7); + + mix_and_propagate(xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7); + } } _mm_store_si128(output + 4, xout0); @@ -309,23 +386,49 @@ 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) +template +static inline void cryptonight_monero_tweak(uint64_t* mem_out, __m128i tmp) { - keccak(input, (int) size, ctx->state0, 200); + mem_out[0] = EXTRACT64(tmp); - VARIANT1_INIT(0); + tmp = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(tmp), _mm_castsi128_ps(tmp))); + uint64_t vh = EXTRACT64(tmp); - cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory); + uint8_t x = vh >> 24; + static const uint16_t table = 0x7531; + const uint8_t index = (((x >> SHIFT) & 6) | (x & 1)) << 1; + vh ^= ((table >> index) & 0x3) << 28; - const uint8_t* l0 = ctx->memory; - uint64_t* h0 = reinterpret_cast(ctx->state0); + 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 MEM = xmrig::cn_select_memory(); + + if (VARIANT > 0 && size < 43) { + memset(output, 0, 32); + return; + } + + xmrig::keccak(input, size, ctx[0]->state); + + VARIANT1_INIT(0) + + cn_explode_scratchpad((__m128i*) ctx[0]->state, (__m128i*) ctx[0]->memory); + + const uint8_t* l0 = ctx[0]->memory; + uint64_t* h0 = reinterpret_cast(ctx[0]->state); 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]); - uint64_t idx0 = h0[0] ^ h0[4]; + uint64_t idx0 = al0; for (size_t i = 0; i < ITERATIONS; i++) { __m128i cx; @@ -337,8 +440,13 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]); cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0)); } - _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); - VARIANT1_1(&l0[idx0 & MASK]); + + if (VARIANT > 0) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + } else { + _mm_store_si128((__m128i *)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx)); + } + idx0 = EXTRACT64(cx); bx0 = cx; @@ -350,39 +458,66 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si 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); - ah0 ^= ch; + if (VARIANT > 0) { + if (VARIANT == xmrig::VARIANT_IPBC) { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } + else { + ((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; + idx0 = d ^ q; + } } - cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0); + cn_implode_scratchpad((__m128i*) ctx[0]->memory, (__m128i*) ctx[0]->state); - keccakf(h0, 24); - extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output); + xmrig::keccakf(h0, 24); + extra_hashes[ctx[0]->state[0] & 3](ctx[0]->state, 200, output); } -template -inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx) +template +inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx) { - keccak(input, (int) size, ctx->state0, 200); - keccak(input + size, (int) size, ctx->state1, 200); + constexpr size_t MASK = xmrig::cn_select_mask(); + constexpr size_t ITERATIONS = xmrig::cn_select_iter(); + constexpr size_t MEM = xmrig::cn_select_memory(); + + if (VARIANT > 0 && size < 43) { + memset(output, 0, 64); + return; + } + + xmrig::keccak(input, size, ctx[0]->state); + xmrig::keccak(input + size, size, ctx[1]->state); VARIANT1_INIT(0); VARIANT1_INIT(1); - const uint8_t* l0 = ctx->memory; - const uint8_t* l1 = ctx->memory + MEM; - uint64_t* h0 = reinterpret_cast(ctx->state0); - uint64_t* h1 = reinterpret_cast(ctx->state1); + 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); - cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0); - cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1); + 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]; @@ -392,8 +527,8 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); - uint64_t idx0 = h0[0] ^ h0[4]; - uint64_t idx1 = h1[0] ^ h1[4]; + uint64_t idx0 = al0; + uint64_t idx1 = al1; for (size_t i = 0; i < ITERATIONS; i++) { __m128i cx0, cx1; @@ -409,10 +544,13 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1)); } - _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); - _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); - VARIANT1_1(&l0[idx0 & MASK]); - VARIANT1_1(&l1[idx1 & MASK]); + if (VARIANT > 0) { + cryptonight_monero_tweak((uint64_t*)&l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); + cryptonight_monero_tweak((uint64_t*)&l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); + } else { + _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0)); + _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1)); + } idx0 = EXTRACT64(cx0); idx1 = EXTRACT64(cx1); @@ -428,15 +566,33 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si 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); + ((uint64_t*)&l0[idx0 & MASK])[0] = al0; + + if (VARIANT > 0) { + if (VARIANT == xmrig::VARIANT_IPBC) { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0 ^ al0; + } + else { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0 ^ tweak1_2_0; + } + } + else { + ((uint64_t*)&l0[idx0 & MASK])[1] = ah0; + } - ah0 ^= ch; 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; + idx0 = d ^ q; + } + cl = ((uint64_t*) &l1[idx1 & MASK])[0]; ch = ((uint64_t*) &l1[idx1 & MASK])[1]; lo = __umul128(idx1, cl, &hi); @@ -444,24 +600,420 @@ inline void cryptonight_double_hash(const uint8_t *__restrict__ input, size_t si al1 += hi; ah1 += lo; - VARIANT1_2(ah1, 1); - ((uint64_t*) &l1[idx1 & MASK])[0] = al1; - ((uint64_t*) &l1[idx1 & MASK])[1] = ah1; - VARIANT1_2(ah1, 1); + ((uint64_t*)&l1[idx1 & MASK])[0] = al1; + + if (VARIANT > 0) { + if (VARIANT == xmrig::VARIANT_IPBC) { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1 ^ al1; + } + else { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1 ^ tweak1_2_1; + } + } + else { + ((uint64_t*)&l1[idx1 & MASK])[1] = ah1; + } - ah1 ^= ch; 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; + idx1 = d ^ q; + } } - cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); - cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); + cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0); + cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1); - keccakf(h0, 24); - keccakf(h1, 24); + xmrig::keccakf(h0, 24); + xmrig::keccakf(h1, 24); - extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output); - extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, output + 32); + 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, b, c, l, ptr, idx) \ + ptr = reinterpret_cast<__m128i*>(&l[idx & MASK]); \ + c = _mm_load_si128(ptr); + + +#define CN_STEP2(a, b, c, l, ptr, idx) \ + if (SOFT_AES) { \ + c = soft_aesenc(c, a); \ + } else { \ + c = _mm_aesenc_si128(c, a); \ + } \ + \ + b = _mm_xor_si128(b, c); \ + \ + if (VARIANT > 0) { \ + cryptonight_monero_tweak(reinterpret_cast(ptr), b); \ + } else { \ + _mm_store_si128(ptr, b); \ + } + + +#define CN_STEP3(a, b, c, l, ptr, idx) \ + idx = EXTRACT64(c); \ + ptr = reinterpret_cast<__m128i*>(&l[idx & MASK]); \ + b = _mm_load_si128(ptr); + + +#define CN_STEP4(a, b, c, l, mc, ptr, idx) \ + lo = __umul128(idx, EXTRACT64(b), &hi); \ + a = _mm_add_epi64(a, _mm_set_epi64x(lo, hi)); \ + \ + if (VARIANT > 0) { \ + _mm_store_si128(ptr, _mm_xor_si128(a, mc)); \ + \ + if (VARIANT == xmrig::VARIANT_IPBC) { \ + ((uint64_t*)ptr)[1] ^= ((uint64_t*)ptr)[0]; \ + } \ + } else { \ + _mm_store_si128(ptr, a); \ + } \ + \ + a = _mm_xor_si128(a, b); \ + idx = EXTRACT64(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; \ + idx = d ^ q; \ + } + + +#define CONST_INIT(ctx, n) \ + __m128i mc##n; \ + if (VARIANT > 0) { \ + mc##n = _mm_set_epi64x(*reinterpret_cast(input + n * size + 35) ^ \ + *(reinterpret_cast((ctx)->state) + 24), 0); \ + } + + +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(); + + if (VARIANT > 0 && size < 43) { + memset(output, 0, 32 * 3); + return; + } + + 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)); + } + + CONST_INIT(ctx[0], 0); + CONST_INIT(ctx[1], 1); + CONST_INIT(ctx[2], 2); + + 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); + + __m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]); + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]); + __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); + __m128i ax2 = _mm_set_epi64x(h2[1] ^ h2[5], h2[0] ^ h2[4]); + __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]); + __m128i cx0 = _mm_set_epi64x(0, 0); + __m128i cx1 = _mm_set_epi64x(0, 0); + __m128i cx2 = _mm_set_epi64x(0, 0); + + uint64_t idx0, idx1, idx2; + idx0 = EXTRACT64(ax0); + idx1 = EXTRACT64(ax1); + idx2 = EXTRACT64(ax2); + + for (size_t i = 0; i < ITERATIONS / 2; i++) { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2; + + // EVEN ROUND + CN_STEP1(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx2, cx2, l2, ptr2, idx2); + + CN_STEP2(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx2, cx2, l2, ptr2, idx2); + + CN_STEP3(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP3(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP3(ax2, bx2, cx2, l2, ptr2, idx2); + + CN_STEP4(ax0, bx0, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, bx1, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, bx2, cx2, l2, mc2, ptr2, idx2); + + // ODD ROUND + CN_STEP1(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP1(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP1(ax2, cx2, bx2, l2, ptr2, idx2); + + CN_STEP2(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP2(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP2(ax2, cx2, bx2, l2, ptr2, idx2); + + CN_STEP3(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP3(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP3(ax2, cx2, bx2, l2, ptr2, idx2); + + CN_STEP4(ax0, cx0, bx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, cx1, bx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, cx2, bx2, 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); + } +} + + +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(); + + if (VARIANT > 0 && 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)); + } + + CONST_INIT(ctx[0], 0); + CONST_INIT(ctx[1], 1); + CONST_INIT(ctx[2], 2); + CONST_INIT(ctx[3], 3); + + 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); + + __m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]); + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]); + __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); + __m128i ax2 = _mm_set_epi64x(h2[1] ^ h2[5], h2[0] ^ h2[4]); + __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]); + __m128i ax3 = _mm_set_epi64x(h3[1] ^ h3[5], h3[0] ^ h3[4]); + __m128i bx3 = _mm_set_epi64x(h3[3] ^ h3[7], h3[2] ^ h3[6]); + __m128i cx0 = _mm_set_epi64x(0, 0); + __m128i cx1 = _mm_set_epi64x(0, 0); + __m128i cx2 = _mm_set_epi64x(0, 0); + __m128i cx3 = _mm_set_epi64x(0, 0); + + uint64_t idx0, idx1, idx2, idx3; + idx0 = EXTRACT64(ax0); + idx1 = EXTRACT64(ax1); + idx2 = EXTRACT64(ax2); + idx3 = EXTRACT64(ax3); + + for (size_t i = 0; i < ITERATIONS / 2; i++) + { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2, *ptr3; + + // EVEN ROUND + CN_STEP1(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP1(ax3, bx3, cx3, l3, ptr3, idx3); + + CN_STEP2(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP2(ax3, bx3, cx3, l3, ptr3, idx3); + + CN_STEP3(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP3(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP3(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP3(ax3, bx3, cx3, l3, ptr3, idx3); + + CN_STEP4(ax0, bx0, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, bx1, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, bx2, cx2, l2, mc2, ptr2, idx2); + CN_STEP4(ax3, bx3, cx3, l3, mc3, ptr3, idx3); + + // ODD ROUND + CN_STEP1(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP1(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP1(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP1(ax3, cx3, bx3, l3, ptr3, idx3); + + CN_STEP2(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP2(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP2(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP2(ax3, cx3, bx3, l3, ptr3, idx3); + + CN_STEP3(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP3(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP3(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP3(ax3, cx3, bx3, l3, ptr3, idx3); + + CN_STEP4(ax0, cx0, bx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, cx1, bx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, cx2, bx2, l2, mc2, ptr2, idx2); + CN_STEP4(ax3, cx3, bx3, 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(); + + if (VARIANT > 0 && 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)); + } + + 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); + + 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); + + __m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]); + __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); + __m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]); + __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); + __m128i ax2 = _mm_set_epi64x(h2[1] ^ h2[5], h2[0] ^ h2[4]); + __m128i bx2 = _mm_set_epi64x(h2[3] ^ h2[7], h2[2] ^ h2[6]); + __m128i ax3 = _mm_set_epi64x(h3[1] ^ h3[5], h3[0] ^ h3[4]); + __m128i bx3 = _mm_set_epi64x(h3[3] ^ h3[7], h3[2] ^ h3[6]); + __m128i ax4 = _mm_set_epi64x(h4[1] ^ h4[5], h4[0] ^ h4[4]); + __m128i bx4 = _mm_set_epi64x(h4[3] ^ h4[7], h4[2] ^ h4[6]); + __m128i cx0 = _mm_set_epi64x(0, 0); + __m128i cx1 = _mm_set_epi64x(0, 0); + __m128i cx2 = _mm_set_epi64x(0, 0); + __m128i cx3 = _mm_set_epi64x(0, 0); + __m128i cx4 = _mm_set_epi64x(0, 0); + + uint64_t idx0, idx1, idx2, idx3, idx4; + idx0 = EXTRACT64(ax0); + idx1 = EXTRACT64(ax1); + idx2 = EXTRACT64(ax2); + idx3 = EXTRACT64(ax3); + idx4 = EXTRACT64(ax4); + + for (size_t i = 0; i < ITERATIONS / 2; i++) + { + uint64_t hi, lo; + __m128i *ptr0, *ptr1, *ptr2, *ptr3, *ptr4; + + // EVEN ROUND + CN_STEP1(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP1(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP1(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP1(ax3, bx3, cx3, l3, ptr3, idx3); + CN_STEP1(ax4, bx4, cx4, l4, ptr4, idx4); + + CN_STEP2(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP2(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP2(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP2(ax3, bx3, cx3, l3, ptr3, idx3); + CN_STEP2(ax4, bx4, cx4, l4, ptr4, idx4); + + CN_STEP3(ax0, bx0, cx0, l0, ptr0, idx0); + CN_STEP3(ax1, bx1, cx1, l1, ptr1, idx1); + CN_STEP3(ax2, bx2, cx2, l2, ptr2, idx2); + CN_STEP3(ax3, bx3, cx3, l3, ptr3, idx3); + CN_STEP3(ax4, bx4, cx4, l4, ptr4, idx4); + + CN_STEP4(ax0, bx0, cx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, bx1, cx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, bx2, cx2, l2, mc2, ptr2, idx2); + CN_STEP4(ax3, bx3, cx3, l3, mc3, ptr3, idx3); + CN_STEP4(ax4, bx4, cx4, l4, mc4, ptr4, idx4); + + // ODD ROUND + CN_STEP1(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP1(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP1(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP1(ax3, cx3, bx3, l3, ptr3, idx3); + CN_STEP1(ax4, cx4, bx4, l4, ptr4, idx4); + + CN_STEP2(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP2(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP2(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP2(ax3, cx3, bx3, l3, ptr3, idx3); + CN_STEP2(ax4, cx4, bx4, l4, ptr4, idx4); + + CN_STEP3(ax0, cx0, bx0, l0, ptr0, idx0); + CN_STEP3(ax1, cx1, bx1, l1, ptr1, idx1); + CN_STEP3(ax2, cx2, bx2, l2, ptr2, idx2); + CN_STEP3(ax3, cx3, bx3, l3, ptr3, idx3); + CN_STEP3(ax4, cx4, bx4, l4, ptr4, idx4); + + CN_STEP4(ax0, cx0, bx0, l0, mc0, ptr0, idx0); + CN_STEP4(ax1, cx1, bx1, l1, mc1, ptr1, idx1); + CN_STEP4(ax2, cx2, bx2, l2, mc2, ptr2, idx2); + CN_STEP4(ax3, cx3, bx3, l3, mc3, ptr3, idx3); + CN_STEP4(ax4, cx4, bx4, 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 /* __CRYPTONIGHT_X86_H__ */ diff --git a/src/crypto/c_keccak.h b/src/crypto/c_keccak.h deleted file mode 100644 index 4f7f8572..00000000 --- a/src/crypto/c_keccak.h +++ /dev/null @@ -1,26 +0,0 @@ -// keccak.h -// 19-Nov-11 Markku-Juhani O. Saarinen - -#ifndef KECCAK_H -#define KECCAK_H - -#include -#include - -#ifndef KECCAK_ROUNDS -#define KECCAK_ROUNDS 24 -#endif - -#ifndef ROTL64 -#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) -#endif - -// compute a keccak hash (md) of given byte length from "in" -int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen); - -// update the state -void keccakf(uint64_t st[25], int norounds); - -void keccak1600(const uint8_t *in, int inlen, uint8_t *md); - -#endif 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 e8230b87..46f26b73 100644 --- a/src/donate.h +++ b/src/donate.h @@ -29,16 +29,22 @@ * Dev donation. * * Percentage of your hashing power that you want to donate to the developer, can be 0 if you don't want to do that. - * Example of how it works for the default setting of 1: - * You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1 minute. - * Since v2.5.1 start time randomized in range from 50 to 150 minutes minus donation time. + * + * Example of how it works for the setting of 1%: + * You miner will mine into your usual pool for random time (in range from 49.5 to 148.5 minutes), + * then switch to the developer's pool for 1 minute, then switch again to your pool for 99 minutes + * and then switch agaiin to developer's pool for 1 minute, these rounds will continue until miner working. + * + * Randomised only first round, to prevent waves on the donation pool. + * * Switching is instant, and only happens after a successful connection, so you never loose any hashes. * * If you plan on changing this setting to 0 please consider making a one off donation to my wallet: * XMR: 48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD * BTC: 1P7ujsXeX7GxQwHNnJsRMgAdNkFZmNVqJT */ -constexpr const int kDonateLevel = 5; +constexpr const int kDefaultDonateLevel = 5; +constexpr const int kMinimumDonateLevel = 1; #endif /* __DONATE_H__ */ diff --git a/src/interfaces/IConfig.h b/src/interfaces/IConfig.h new file mode 100644 index 00000000..2422b891 --- /dev/null +++ b/src/interfaces/IConfig.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 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 __ICONFIG_H__ +#define __ICONFIG_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, + 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, + + // 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, + + // xmrig-proxy + AccessLogFileKey = 'A', + BindKey = 'b', + CoinKey = 1104, + CustomDiffKey = 1102, + DebugKey = 1101, + ModeKey = 'm', + PoolCoinKey = 'C', + ReuseTimeoutKey = 1106, + WorkersKey = 1103, + }; + + 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 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 // __ICONFIG_H__ diff --git a/src/interfaces/IConfigCreator.h b/src/interfaces/IConfigCreator.h new file mode 100644 index 00000000..597a6b74 --- /dev/null +++ b/src/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/workers/SingleWorker.h b/src/interfaces/IControllerListener.h similarity index 71% rename from src/workers/SingleWorker.h rename to src/interfaces/IControllerListener.h index f7d9cff8..d6077138 100644 --- a/src/workers/SingleWorker.h +++ b/src/interfaces/IControllerListener.h @@ -5,7 +5,6 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett * Copyright 2016-2018 XMRig , * * This program is free software: you can redistribute it and/or modify @@ -22,34 +21,26 @@ * along with this program. If not, see . */ -#ifndef __SINGLEWORKER_H__ -#define __SINGLEWORKER_H__ +#ifndef __ICONTROLLERLISTENER_H__ +#define __ICONTROLLERLISTENER_H__ -#include "net/Job.h" -#include "net/JobResult.h" -#include "workers/Worker.h" +namespace xmrig { -class Handle; +class Config; -class SingleWorker : public Worker +class IControllerListener { public: - SingleWorker(Handle *handle); + virtual ~IControllerListener() {} - void start() override; - -private: - bool resume(const Job &job); - void consumeJob(); - void save(const Job &job); - - Job m_job; - Job m_paused; - JobResult m_result; + virtual void onConfigChanged(Config *config, Config *previousConfig) = 0; }; -#endif /* __SINGLEWORKER_H__ */ +} /* namespace xmrig */ + + +#endif // __ICONTROLLERLISTENER_H__ diff --git a/src/interfaces/IThread.h b/src/interfaces/IThread.h new file mode 100644 index 00000000..2e9e3c39 --- /dev/null +++ b/src/interfaces/IThread.h @@ -0,0 +1,73 @@ +/* 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 __ITHREAD_H__ +#define __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 +}; + + +} /* namespace xmrig */ + + +#endif // __ITHREAD_H__ diff --git a/src/interfaces/IWatcherListener.h b/src/interfaces/IWatcherListener.h new file mode 100644 index 00000000..bfafb9a0 --- /dev/null +++ b/src/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/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..4a920ca0 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -29,41 +29,24 @@ #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)); } - 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; - } - - inline uint64_t actualDiff() const { return Job::toDiff(reinterpret_cast(result)[3]); @@ -74,6 +57,7 @@ public: 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 ede3f8b4..7293a0ac 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->algo(), 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,7 @@ 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()); + LOG_INFO(isColors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); } @@ -146,26 +146,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..353edc77 100644 --- a/src/net/Network.h +++ b/src/net/Network.h @@ -35,14 +35,18 @@ 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 @@ protected: 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/Url.cpp b/src/net/Url.cpp deleted file mode 100644 index 99fe9dc2..00000000 --- a/src/net/Url.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* 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 "net/Url.h" -#include "xmrig.h" - - -#ifdef _MSC_VER -# define strncasecmp(x,y,z) _strnicmp(x,y,z) -#endif - - -Url::Url() : - m_keepAlive(false), - m_nicehash(false), - m_host(nullptr), - m_password(nullptr), - m_user(nullptr), - m_algo(xmrig::ALGO_CRYPTONIGHT), - m_variant(xmrig::VARIANT_AUTO), - m_url(nullptr), - m_port(kDefaultPort) -{ -} - - -/** - * @brief Parse url. - * - * Valid urls: - * example.com - * example.com:3333 - * stratum+tcp://example.com - * stratum+tcp://example.com:3333 - * - * @param url - */ -Url::Url(const char *url) : - m_keepAlive(false), - m_nicehash(false), - m_host(nullptr), - m_password(nullptr), - m_user(nullptr), - m_algo(xmrig::ALGO_CRYPTONIGHT), - m_variant(xmrig::VARIANT_AUTO), - m_url(nullptr), - m_port(kDefaultPort) -{ - parse(url); -} - - -Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool keepAlive, bool nicehash, int variant) : - m_keepAlive(keepAlive), - m_nicehash(nicehash), - m_password(password ? strdup(password) : nullptr), - m_user(user ? strdup(user) : nullptr), - m_algo(xmrig::ALGO_CRYPTONIGHT), - m_variant(variant), - m_url(nullptr), - m_port(port) -{ - m_host = strdup(host); -} - - -Url::~Url() -{ - free(m_host); - free(m_password); - free(m_user); - - if (m_url) { - delete [] m_url; - } -} - - -bool Url::parse(const char *url) -{ - const char *p = strstr(url, "://"); - const char *base = url; - - if (p) { - if (strncasecmp(url, "stratum+tcp://", 14)) { - return false; - } - - base = url + 14; - } - - if (!strlen(base) || *base == '/') { - return false; - } - - if (base[0] == '[') { - return parseIPv6(base); - } - - const char *port = strchr(base, ':'); - if (!port) { - m_host = strdup(base); - return false; - } - - const size_t size = port++ - base + 1; - m_host = new char[size](); - memcpy(m_host, base, size - 1); - - m_port = (uint16_t) strtol(port, nullptr, 10); - return true; -} - - -bool Url::setUserpass(const char *userpass) -{ - const char *p = strchr(userpass, ':'); - if (!p) { - return false; - } - - free(m_user); - free(m_password); - - m_user = static_cast(calloc(p - userpass + 1, 1)); - strncpy(m_user, userpass, p - userpass); - m_password = strdup(p + 1); - - return true; -} - - -const char *Url::url() const -{ - if (!m_url) { - const size_t size = strlen(m_host) + 8; - m_url = new char[size]; - - snprintf(m_url, size - 1, "%s:%d", m_host, m_port); - } - - return m_url; -} - - -void Url::adjust(int algo) -{ - if (!isValid()) { - return; - } - - m_algo = algo; - - if (strstr(m_host, ".nicehash.com")) { - m_keepAlive = false; - m_nicehash = true; - - if (strstr(m_host, "cryptonightv7.")) { - m_variant = xmrig::VARIANT_V1; - } - } - - if (strstr(m_host, ".minergate.com")) { - m_keepAlive = false; - } -} - - -void Url::setPassword(const char *password) -{ - if (!password) { - return; - } - - free(m_password); - m_password = strdup(password); -} - - -void Url::setUser(const char *user) -{ - if (!user) { - return; - } - - free(m_user); - m_user = strdup(user); -} - - -void Url::setVariant(int variant) -{ - switch (variant) { - case xmrig::VARIANT_AUTO: - case xmrig::VARIANT_NONE: - case xmrig::VARIANT_V1: - m_variant = variant; - break; - - default: - break; - } -} - - -bool Url::operator==(const Url &other) const -{ - if (m_port != other.m_port || m_keepAlive != other.m_keepAlive || m_nicehash != other.m_nicehash) { - return false; - } - - if (strcmp(host(), other.host()) != 0 || strcmp(user(), other.user()) != 0 || strcmp(password(), other.password()) != 0) { - return false; - } - - return true; -} - - -Url &Url::operator=(const Url *other) -{ - m_keepAlive = other->m_keepAlive; - m_algo = other->m_algo; - m_variant = other->m_variant; - m_nicehash = other->m_nicehash; - m_port = other->m_port; - - free(m_host); - m_host = strdup(other->m_host); - - setPassword(other->m_password); - setUser(other->m_user); - - if (m_url) { - delete [] m_url; - m_url = nullptr; - } - - return *this; -} - - -bool Url::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; - m_host = new char[size](); - memcpy(m_host, addr + 1, size - 1); - - m_port = (uint16_t) strtol(port + 1, nullptr, 10); - - return true; -} diff --git a/src/net/Url.h b/src/net/Url.h deleted file mode 100644 index f861fec5..00000000 --- a/src/net/Url.h +++ /dev/null @@ -1,81 +0,0 @@ -/* 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 __URL_H__ -#define __URL_H__ - - -#include - - -class Url -{ -public: - constexpr static const char *kDefaultPassword = "x"; - constexpr static const char *kDefaultUser = "x"; - constexpr static uint16_t kDefaultPort = 3333; - - Url(); - Url(const char *url); - Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool keepAlive = false, bool nicehash = false, int variant = -1); - ~Url(); - - inline bool isKeepAlive() const { return m_keepAlive; } - inline bool isNicehash() const { return m_nicehash; } - inline bool isValid() const { return m_host && m_port > 0; } - inline const char *host() const { return m_host; } - inline const char *password() const { return m_password ? m_password : kDefaultPassword; } - inline const char *user() const { return m_user ? m_user : kDefaultUser; } - inline int algo() const { return m_algo; } - inline int variant() const { return m_variant; } - inline uint16_t port() const { return m_port; } - inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } - inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } - inline void setVariant(bool monero) { m_variant = monero; } - - bool parse(const char *url); - bool setUserpass(const char *userpass); - const char *url() const; - void adjust(int algo); - void setPassword(const char *password); - void setUser(const char *user); - void setVariant(int variant); - - bool operator==(const Url &other) const; - Url &operator=(const Url *other); - -private: - bool parseIPv6(const char *addr); - - bool m_keepAlive; - bool m_nicehash; - char *m_host; - char *m_password; - char *m_user; - int m_algo; - int m_variant; - mutable char *m_url; - uint16_t m_port; -}; - -#endif /* __URL_H__ */ diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index ae707e21..b4b41938 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -22,31 +22,27 @@ */ +#include "common/crypto/keccak.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 "interfaces/IStrategyListener.h" -#include "net/Client.h" -#include "net/Job.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 = "miner.fee.xmrig.com"; const static char *kDonatePool2 = "emergency.fee.xmrig.com"; -static inline int random(int min, int max){ - return min + rand() / (RAND_MAX / (max - min + 1) + 1); +static inline float randomf(float min, float max) { + return (max - min) * ((((float) rand()) / (float) RAND_MAX)) + min; } -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,25 +52,36 @@ 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::ALGO_CRYPTONIGHT) { - m_pools.push_back(new Url(kDonatePool1, 6666, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool1, 80, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool2, 5555, "48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD", "emergency", false, false)); + if (algo == xmrig::CRYPTONIGHT) { + m_pools.push_back(Pool(kDonatePool1, 6666, userId, nullptr, false, true)); + m_pools.push_back(Pool(kDonatePool1, 80, userId, nullptr, false, true)); + m_pools.push_back(Pool(kDonatePool2, 5555, "48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD", "emergency", false, false)); + } + else if (algo == xmrig::CRYPTONIGHT_HEAVY) { + m_pools.push_back(Pool(kDonatePool1, 8888, userId, nullptr, false, true)); } else { - m_pools.push_back(new Url(kDonatePool1, 5555, userId, nullptr, false, true)); - m_pools.push_back(new Url(kDonatePool1, 7777, userId, nullptr, false, true)); + m_pools.push_back(Pool(kDonatePool1, 5555, userId, nullptr, false, true)); } - m_strategy = new FailoverStrategy(m_pools, 1, 1, this, true); + for (Pool &pool : m_pools) { + pool.algorithm().setAlgo(algo); + } + + if (m_pools.size() > 1) { + m_strategy = new FailoverStrategy(m_pools, 1, 2, this, true); + } + else { + m_strategy = new SinglePoolStrategy(m_pools.front(), 1, 2, this, true); + } m_timer.data = this; uv_timer_init(uv_default_loop(), &m_timer); - idle(random(3000, 9000) * 1000 - m_donateTime); + idle(m_idleTime * randomf(0.5, 1.5)); } diff --git a/src/net/strategies/DonateStrategy.h b/src/net/strategies/DonateStrategy.h index 4ef29958..66c0375c 100644 --- a/src/net/strategies/DonateStrategy.h +++ b/src/net/strategies/DonateStrategy.h @@ -29,6 +29,7 @@ #include +#include "common/net/Pool.h" #include "interfaces/IClientListener.h" #include "interfaces/IStrategy.h" #include "interfaces/IStrategyListener.h" @@ -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,7 +72,7 @@ private: const int m_idleTime; IStrategy *m_strategy; IStrategyListener *m_listener; - std::vector m_pools; + std::vector m_pools; uv_timer_t m_timer; }; diff --git a/src/version.h b/src/version.h index 4b44f2e8..b0e4d2a5 100644 --- a/src/version.h +++ b/src/version.h @@ -27,16 +27,15 @@ #define APP_ID "xmrig" #define APP_NAME "XMRig" #define APP_DESC "XMRig CPU miner" -#define APP_VERSION "2.5.3" +#define APP_VERSION "2.6.1-dev" #define APP_DOMAIN "xmrig.com" #define APP_SITE "www.xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2018 xmrig.com" #define APP_KIND "cpu" #define APP_VER_MAJOR 2 -#define APP_VER_MINOR 5 -#define APP_VER_BUILD 3 -#define APP_VER_REV 0 +#define APP_VER_MINOR 6 +#define APP_VER_PATCH 1 #ifdef _MSC_VER # if (_MSC_VER >= 1910) diff --git a/src/workers/CpuThread.cpp b/src/workers/CpuThread.cpp new file mode 100644 index 00000000..e42139c0 --- /dev/null +++ b/src/workers/CpuThread.cpp @@ -0,0 +1,316 @@ +/* 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/Pool.h" +#include "rapidjson/document.h" +#include "workers/CpuThread.h" + + +#if defined(XMRIG_ARM) +# include "crypto/CryptoNight_arm.h" +#else +# include "crypto/CryptoNight_x86.h" +#endif + + +xmrig::CpuThread::CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch) : + m_algorithm(algorithm), + m_av(av), + m_prefetch(prefetch), + m_softAES(softAES), + m_priority(priority), + m_affinity(affinity), + m_multiway(multiway), + m_index(index) +{ +} + + +xmrig::CpuThread::~CpuThread() +{ +} + + +bool xmrig::CpuThread::isSoftAES(AlgoVariant av) +{ + return av == AV_SINGLE_SOFT || av == AV_DOUBLE_SOFT || av > AV_PENTA; +} + + +xmrig::CpuThread::cn_hash_fun xmrig::CpuThread::fn(Algo algorithm, AlgoVariant av, Variant variant) +{ + assert(variant == VARIANT_0 || variant == VARIANT_1 || variant == VARIANT_IPBC || variant == VARIANT_XTL); + + static const cn_hash_fun func_table[90] = { + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + +# ifndef XMRIG_NO_AEON + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +# else + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, 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_double_hash, + cryptonight_single_hash, + cryptonight_double_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, + cryptonight_triple_hash, + cryptonight_quad_hash, + cryptonight_penta_hash, +# else + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, +# endif + }; + +# ifndef XMRIG_NO_SUMO + if (algorithm == CRYPTONIGHT_HEAVY) { + variant = VARIANT_0; + } +# endif + + const size_t index = 40 * algorithm + 10 * variant + av - 1; + +# ifndef NDEBUG + cn_hash_fun func = func_table[index]; + + assert(index < sizeof(func_table) / sizeof(func_table[0])); + assert(func != nullptr); + + return func; +# else + return func_table[index]; +# endif +} + + +xmrig::CpuThread *xmrig::CpuThread::createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority) +{ + assert(av > AV_AUTO && av < AV_MAX); + + int64_t cpuId = -1L; + + if (affinity != -1L) { + size_t idx = 0; + + for (size_t i = 0; i < 64; i++) { + if (!(affinity & (1ULL << i))) { + continue; + } + + if (idx == index) { + cpuId = i; + break; + } + + idx++; + } + } + + return new CpuThread(index, algorithm, av, multiway(av), cpuId, priority, isSoftAES(av), false); +} + + +xmrig::CpuThread *xmrig::CpuThread::createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES) +{ + int av = AV_AUTO; + const Multiway multiway = data.multiway; + + if (multiway <= DoubleWay) { + av = softAES ? (multiway + 2) : multiway; + } + else { + av = softAES ? (multiway + 5) : (multiway + 2); + } + + assert(av > AV_AUTO && av < AV_MAX); + + return new CpuThread(index, algorithm, static_cast(av), multiway, data.affinity, priority, softAES, false); +} + + +xmrig::CpuThread::Data xmrig::CpuThread::parse(const rapidjson::Value &object) +{ + Data data; + + const auto &multiway = object["low_power_mode"]; + if (multiway.IsBool()) { + data.multiway = multiway.IsTrue() ? DoubleWay : SingleWay; + data.valid = true; + } + else if (multiway.IsUint()) { + data.setMultiway(multiway.GetInt()); + } + + if (!data.valid) { + return data; + } + + const auto &affinity = object["affine_to_cpu"]; + + if (affinity.IsUint64()) { + data.affinity = affinity.GetInt64(); + } + + return data; +} + + +xmrig::IThread::Multiway xmrig::CpuThread::multiway(AlgoVariant av) +{ + switch (av) { + case AV_SINGLE: + case AV_SINGLE_SOFT: + return SingleWay; + + case AV_DOUBLE_SOFT: + case AV_DOUBLE: + return DoubleWay; + + case AV_TRIPLE_SOFT: + case AV_TRIPLE: + return TripleWay; + + case AV_QUAD_SOFT: + case AV_QUAD: + return QuadWay; + + case AV_PENTA_SOFT: + case AV_PENTA: + return PentaWay; + + default: + break; + } + + return SingleWay; +} + + +#ifndef XMRIG_NO_API +rapidjson::Value xmrig::CpuThread::toAPI(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + Value obj(kObjectType); + auto &allocator = doc.GetAllocator(); + + obj.AddMember("type", "cpu", allocator); + obj.AddMember("av", m_av, allocator); + obj.AddMember("low_power_mode", multiway(), allocator); + obj.AddMember("affine_to_cpu", affinity(), allocator); + obj.AddMember("priority", priority(), allocator); + obj.AddMember("soft_aes", isSoftAES(), allocator); + + return obj; +} +#endif + + +rapidjson::Value xmrig::CpuThread::toConfig(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + Value obj(kObjectType); + auto &allocator = doc.GetAllocator(); + + obj.AddMember("low_power_mode", multiway(), allocator); + obj.AddMember("affine_to_cpu", affinity() == -1L ? Value(kFalseType) : Value(affinity()), allocator); + + return obj; +} diff --git a/src/workers/CpuThread.h b/src/workers/CpuThread.h new file mode 100644 index 00000000..0e364764 --- /dev/null +++ b/src/workers/CpuThread.h @@ -0,0 +1,104 @@ +/* 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 __CPUTHREAD_H__ +#define __CPUTHREAD_H__ + + +#include "common/xmrig.h" +#include "interfaces/IThread.h" + + +struct cryptonight_ctx; + + +namespace xmrig { + + +class CpuThread : public IThread +{ +public: + struct Data + { + inline Data() : valid(false), affinity(-1L), multiway(SingleWay) {} + + inline void setMultiway(int value) + { + if (value >= SingleWay && value <= PentaWay) { + multiway = static_cast(value); + valid = true; + } + } + + bool valid; + int64_t affinity; + Multiway multiway; + }; + + + CpuThread(size_t index, Algo algorithm, AlgoVariant av, Multiway multiway, int64_t affinity, int priority, bool softAES, bool prefetch); + ~CpuThread(); + + typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx); + + static bool isSoftAES(AlgoVariant av); + static cn_hash_fun fn(Algo algorithm, AlgoVariant av, Variant variant); + static CpuThread *createFromAV(size_t index, Algo algorithm, AlgoVariant av, int64_t affinity, int priority); + static CpuThread *createFromData(size_t index, Algo algorithm, const CpuThread::Data &data, int priority, bool softAES); + static Data parse(const rapidjson::Value &object); + static Multiway multiway(AlgoVariant av); + + inline bool isPrefetch() const { return m_prefetch; } + inline bool isSoftAES() const { return m_softAES; } + inline cn_hash_fun fn(Variant variant) const { return fn(m_algorithm, m_av, variant); } + + inline Algo algorithm() const override { return m_algorithm; } + inline int priority() const override { return m_priority; } + inline int64_t affinity() const override { return m_affinity; } + inline Multiway multiway() const override { return m_multiway; } + inline size_t index() const override { return m_index; } + inline Type type() const override { return CPU; } + +protected: +# ifndef XMRIG_NO_API + rapidjson::Value toAPI(rapidjson::Document &doc) const override; +# endif + + rapidjson::Value toConfig(rapidjson::Document &doc) const override; + +private: + const Algo m_algorithm; + const AlgoVariant m_av; + const bool m_prefetch; + const bool m_softAES; + const int m_priority; + const int64_t m_affinity; + const Multiway m_multiway; + const size_t m_index; +}; + + +} /* namespace xmrig */ + + +#endif /* __CPUTHREAD_H__ */ diff --git a/src/workers/DoubleWorker.cpp b/src/workers/DoubleWorker.cpp deleted file mode 100644 index 46c8ed2e..00000000 --- a/src/workers/DoubleWorker.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* 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 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 "crypto/CryptoNight.h" -#include "workers/DoubleWorker.h" -#include "workers/Workers.h" - - -class DoubleWorker::State -{ -public: - inline State() : - nonce1(0), - nonce2(0) - {} - - Job job; - uint32_t nonce1; - uint32_t nonce2; - uint8_t blob[84 * 2]; -}; - - -DoubleWorker::DoubleWorker(Handle *handle) - : Worker(handle) -{ - m_state = new State(); - m_pausedState = new State(); -} - - -DoubleWorker::~DoubleWorker() -{ - delete m_state; - delete m_pausedState; -} - - -void DoubleWorker::start() -{ - while (Workers::sequence() > 0) { - if (Workers::isPaused()) { - do { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - while (Workers::isPaused()); - - if (Workers::sequence() == 0) { - break; - } - - consumeJob(); - } - - while (!Workers::isOutdated(m_sequence)) { - if ((m_count & 0xF) == 0) { - storeStats(); - } - - m_count += 2; - *Job::nonce(m_state->blob) = ++m_state->nonce1; - *Job::nonce(m_state->blob + m_state->job.size()) = ++m_state->nonce2; - - CryptoNight::hash(m_state->blob, m_state->job.size(), m_hash, m_ctx, m_state->job.variant()); - - if (*reinterpret_cast(m_hash + 24) < m_state->job.target()) { - Workers::submit(JobResult(m_state->job.poolId(), m_state->job.id(), m_state->nonce1, m_hash, m_state->job.diff())); - } - - if (*reinterpret_cast(m_hash + 32 + 24) < m_state->job.target()) { - Workers::submit(JobResult(m_state->job.poolId(), m_state->job.id(), m_state->nonce2, m_hash + 32, m_state->job.diff())); - } - - std::this_thread::yield(); - } - - consumeJob(); - } -} - - -bool DoubleWorker::resume(const Job &job) -{ - if (m_state->job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_pausedState->job.id()) { - *m_state = *m_pausedState; - return true; - } - - return false; -} - - -void DoubleWorker::consumeJob() -{ - Job job = Workers::job(); - m_sequence = Workers::sequence(); - if (m_state->job == job) { - return; - } - - save(job); - - if (resume(job)) { - return; - } - - m_state->job = std::move(job); - memcpy(m_state->blob, m_state->job.blob(), m_state->job.size()); - memcpy(m_state->blob + m_state->job.size(), m_state->job.blob(), m_state->job.size()); - - if (m_state->job.isNicehash()) { - m_state->nonce1 = (*Job::nonce(m_state->blob) & 0xff000000U) + (0xffffffU / (m_threads * 2) * m_id); - m_state->nonce2 = (*Job::nonce(m_state->blob + m_state->job.size()) & 0xff000000U) + (0xffffffU / (m_threads * 2) * (m_id + m_threads)); - } - else { - m_state->nonce1 = 0xffffffffU / (m_threads * 2) * m_id; - m_state->nonce2 = 0xffffffffU / (m_threads * 2) * (m_id + m_threads); - } -} - - -void DoubleWorker::save(const Job &job) -{ - if (job.poolId() == -1 && m_state->job.poolId() >= 0) { - *m_pausedState = *m_state; - } -} diff --git a/src/workers/Handle.cpp b/src/workers/Handle.cpp index c461cee7..d42ea368 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 @@ -25,12 +25,11 @@ #include "workers/Handle.h" -Handle::Handle(int threadId, int threads, int64_t affinity, int priority) : - m_priority(priority), - m_threadId(threadId), - m_threads(threads), - m_affinity(affinity), - m_worker(nullptr) +Handle::Handle(xmrig::IThread *config, uint32_t offset, size_t totalWays) : + m_worker(nullptr), + m_totalWays(totalWays), + m_offset(offset), + m_config(config) { } diff --git a/src/workers/Handle.h b/src/workers/Handle.h index 9faae0d0..4bb899f9 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 @@ -25,34 +25,37 @@ #define __HANDLE_H__ +#include #include #include +#include "interfaces/IThread.h" + + class IWorker; class Handle { public: - Handle(int threadId, int threads, int64_t affinity, int priority); + Handle(xmrig::IThread *config, uint32_t offset, size_t totalWays); void join(); void start(void (*callback) (void *)); - inline int priority() const { return m_priority; } - inline int threadId() const { return m_threadId; } - inline int threads() const { return m_threads; } - inline int64_t affinity() const { return m_affinity; } inline IWorker *worker() const { return m_worker; } - inline void setWorker(IWorker *worker) { m_worker = worker; } + inline size_t threadId() const { return m_config->index(); } + 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: - int m_priority; - int m_threadId; - int m_threads; - int64_t m_affinity; IWorker *m_worker; + size_t m_totalWays; + uint32_t m_offset; uv_thread_t m_thread; + xmrig::IThread *m_config; }; diff --git a/src/workers/Hashrate.cpp b/src/workers/Hashrate.cpp index bd5b7df6..42068eb7 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,13 +22,16 @@ */ +#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" @@ -43,24 +46,22 @@ 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; - - memset(m_counts[0], 0, sizeof(uint64_t) * kBucketSize); - memset(m_timestamps[0], 0, sizeof(uint64_t) * kBucketSize); + 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 = Options::i()->printTime(); + const int printTime = controller->config()->printTime(); if (printTime > 0) { uv_timer_init(uv_default_loop(), &m_timer); @@ -76,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; @@ -89,6 +90,8 @@ double Hashrate::calc(size_t ms) const double Hashrate::calc(size_t threadId, size_t ms) const { + assert(threadId < m_threads); + using namespace std::chrono; const uint64_t now = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); @@ -148,12 +151,12 @@ void Hashrate::add(size_t threadId, uint64_t count, uint64_t timestamp) void Hashrate::print() { - 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 2.5s/60s/15m \x1B[01;36m%s \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m max: \x1B[01;36m%s H/s" : "speed 2.5s/60s/15m %s %s %s H/s max: %s H/s", + LOG_INFO(m_controller->config()->isColors() ? "\x1B[01;37mspeed\x1B[0m 2.5s/60s/15m \x1B[01;36m%s \x1B[22;36m%s %s \x1B[01;36mH/s\x1B[0m max: \x1B[01;36m%s H/s" : "speed 2.5s/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)), diff --git a/src/workers/Hashrate.h b/src/workers/Hashrate.h index 026c0cdf..e79c757a 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 @@ -29,6 +29,11 @@ #include +namespace xmrig { + class Controller; +} + + class Hashrate { public: @@ -38,7 +43,7 @@ public: 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); @@ -47,7 +52,7 @@ public: void updateHighest(); inline double highest() const { return m_highest; } - inline int threads() const { return m_threads; } + inline size_t threads() const { return m_threads; } private: static void onReport(uv_timer_t *handle); @@ -56,11 +61,12 @@ private: 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/MultiWorker.cpp b/src/workers/MultiWorker.cpp new file mode 100644 index 00000000..c0f88446 --- /dev/null +++ b/src/workers/MultiWorker.cpp @@ -0,0 +1,193 @@ +/* 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 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 "crypto/CryptoNight_test.h" +#include "workers/CpuThread.h" +#include "workers/MultiWorker.h" +#include "workers/Workers.h" + + +template +MultiWorker::MultiWorker(Handle *handle) + : Worker(handle) +{ + m_memory = Mem::create(m_ctx, m_thread->algorithm(), N); +} + + +template +MultiWorker::~MultiWorker() +{ + Mem::release(m_ctx, N, m_memory); +} + + +template +bool MultiWorker::selfTest() +{ + if (m_thread->fn(xmrig::VARIANT_0) == nullptr) { + return false; + } + + m_thread->fn(xmrig::VARIANT_0)(test_input, 76, m_hash, m_ctx); + + if (m_thread->algorithm() == xmrig::CRYPTONIGHT && memcmp(m_hash, test_output_v0, sizeof m_hash) == 0) { + m_thread->fn(xmrig::VARIANT_1)(test_input, 76, m_hash, m_ctx); + if (memcmp(m_hash, test_output_v1, sizeof m_hash) != 0) { + return false; + } + + m_thread->fn(xmrig::VARIANT_XTL)(test_input, 76, m_hash, m_ctx); + return memcmp(m_hash, test_output_xtl, sizeof m_hash) == 0; + } + +# ifndef XMRIG_NO_AEON + if (m_thread->algorithm() == xmrig::CRYPTONIGHT_LITE && memcmp(m_hash, test_output_v0_lite, sizeof m_hash) == 0) { + m_thread->fn(xmrig::VARIANT_1)(test_input, 76, m_hash, m_ctx); + if (memcmp(m_hash, test_output_v1_lite, sizeof m_hash) != 0) { + return false; + } + + m_thread->fn(xmrig::VARIANT_IPBC)(test_input, 76, m_hash, m_ctx); + return memcmp(m_hash, test_output_ipbc_lite, sizeof m_hash) == 0; + } +# endif + +# ifndef XMRIG_NO_SUMO + return m_thread->algorithm() == xmrig::CRYPTONIGHT_HEAVY && memcmp(m_hash, test_output_heavy, sizeof m_hash) == 0; +# else + return false; +# endif +} + + +template +void MultiWorker::start() +{ + while (Workers::sequence() > 0) { + if (Workers::isPaused()) { + do { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + while (Workers::isPaused()); + + if (Workers::sequence() == 0) { + break; + } + + consumeJob(); + } + + while (!Workers::isOutdated(m_sequence)) { + if ((m_count & 0x7) == 0) { + storeStats(); + } + + m_thread->fn(m_state.job.variant())(m_state.blob, m_state.job.size(), m_hash, m_ctx); + + for (size_t i = 0; i < N; ++i) { + if (*reinterpret_cast(m_hash + (i * 32) + 24) < m_state.job.target()) { + Workers::submit(JobResult(m_state.job.poolId(), m_state.job.id(), *nonce(i), m_hash + (i * 32), m_state.job.diff(), m_state.job.algorithm())); + } + + *nonce(i) += 1; + } + + m_count += N; + + std::this_thread::yield(); + } + + consumeJob(); + } +} + + +template +bool MultiWorker::resume(const Job &job) +{ + if (m_state.job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_pausedState.job.id()) { + m_state = m_pausedState; + return true; + } + + return false; +} + + +template +void MultiWorker::consumeJob() +{ + Job job = Workers::job(); + m_sequence = Workers::sequence(); + if (m_state.job == job) { + return; + } + + save(job); + + if (resume(job)) { + return; + } + + m_state.job = job; + + const size_t size = m_state.job.size(); + memcpy(m_state.blob, m_state.job.blob(), m_state.job.size()); + + if (N > 1) { + for (size_t i = 1; i < N; ++i) { + memcpy(m_state.blob + (i * size), m_state.blob, size); + } + } + + for (size_t i = 0; i < N; ++i) { + if (m_state.job.isNicehash()) { + *nonce(i) = (*nonce(i) & 0xff000000U) + (0xffffffU / m_totalWays * (m_offset + i)); + } + else { + *nonce(i) = 0xffffffffU / m_totalWays * (m_offset + i); + } + } +} + + +template +void MultiWorker::save(const Job &job) +{ + if (job.poolId() == -1 && m_state.job.poolId() >= 0) { + m_pausedState = m_state; + } +} + + +template class MultiWorker<1>; +template class MultiWorker<2>; +template class MultiWorker<3>; +template class MultiWorker<4>; +template class MultiWorker<5>; diff --git a/src/workers/DoubleWorker.h b/src/workers/MultiWorker.h similarity index 70% rename from src/workers/DoubleWorker.h rename to src/workers/MultiWorker.h index 57be59d0..d89bbb33 100644 --- a/src/workers/DoubleWorker.h +++ b/src/workers/MultiWorker.h @@ -22,11 +22,12 @@ * along with this program. If not, see . */ -#ifndef __DOUBLEWORKER_H__ -#define __DOUBLEWORKER_H__ +#ifndef __MULTIWORKER_H__ +#define __MULTIWORKER_H__ -#include "net/Job.h" +#include "common/net/Job.h" +#include "Mem.h" #include "net/JobResult.h" #include "workers/Worker.h" @@ -34,12 +35,15 @@ class Handle; -class DoubleWorker : public Worker +template +class MultiWorker : public Worker { public: - DoubleWorker(Handle *handle); - ~DoubleWorker(); + MultiWorker(Handle *handle); + ~MultiWorker(); +protected: + bool selfTest() override; void start() override; private: @@ -47,12 +51,23 @@ private: void consumeJob(); void save(const Job &job); - class State; + inline uint32_t *nonce(size_t index) + { + return reinterpret_cast(m_state.blob + (index * m_state.job.size()) + 39); + } - uint8_t m_hash[64]; - State *m_state; - State *m_pausedState; + struct State + { + alignas(16) uint8_t blob[96 * N]; + Job job; + }; + + + cryptonight_ctx *m_ctx[N]; + State m_pausedState; + State m_state; + uint8_t m_hash[N * 32]; }; -#endif /* __SINGLEWORKER_H__ */ +#endif /* __MULTIWORKER_H__ */ diff --git a/src/workers/SingleWorker.cpp b/src/workers/SingleWorker.cpp deleted file mode 100644 index 9f4a7484..00000000 --- a/src/workers/SingleWorker.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* 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 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 "crypto/CryptoNight.h" -#include "workers/SingleWorker.h" -#include "workers/Workers.h" - - -SingleWorker::SingleWorker(Handle *handle) - : Worker(handle) -{ -} - - -void SingleWorker::start() -{ - while (Workers::sequence() > 0) { - if (Workers::isPaused()) { - do { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - while (Workers::isPaused()); - - if (Workers::sequence() == 0) { - break; - } - - consumeJob(); - } - - while (!Workers::isOutdated(m_sequence)) { - if ((m_count & 0xF) == 0) { - storeStats(); - } - - m_count++; - *m_job.nonce() = ++m_result.nonce; - - if (CryptoNight::hash(m_job, m_result, m_ctx)) { - Workers::submit(m_result); - } - - std::this_thread::yield(); - } - - consumeJob(); - } -} - - -bool SingleWorker::resume(const Job &job) -{ - if (m_job.poolId() == -1 && job.poolId() >= 0 && job.id() == m_paused.id()) { - m_job = m_paused; - m_result = m_job; - m_result.nonce = *m_job.nonce(); - return true; - } - - return false; -} - - -void SingleWorker::consumeJob() -{ - Job job = Workers::job(); - m_sequence = Workers::sequence(); - if (m_job == job) { - return; - } - - save(job); - - if (resume(job)) { - return; - } - - m_job = std::move(job); - m_result = m_job; - - if (m_job.isNicehash()) { - m_result.nonce = (*m_job.nonce() & 0xff000000U) + (0xffffffU / m_threads * m_id); - } - else { - m_result.nonce = 0xffffffffU / m_threads * m_id; - } -} - - -void SingleWorker::save(const Job &job) -{ - if (job.poolId() == -1 && m_job.poolId() >= 0) { - m_paused = m_job; - } -} diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp index 7a7ff986..567b3e08 100644 --- a/src/workers/Worker.cpp +++ b/src/workers/Worker.cpp @@ -24,32 +24,28 @@ #include +#include "common/Platform.h" #include "Cpu.h" -#include "Mem.h" -#include "Platform.h" +#include "workers/CpuThread.h" #include "workers/Handle.h" #include "workers/Worker.h" Worker::Worker(Handle *handle) : m_id(handle->threadId()), - m_threads(handle->threads()), + m_totalWays(handle->totalWays()), + m_offset(handle->offset()), m_hashCount(0), m_timestamp(0), m_count(0), - m_sequence(0) + m_sequence(0), + m_thread(static_cast(handle->config())) { - if (Cpu::threads() > 1 && handle->affinity() != -1L) { - Cpu::setAffinity(m_id, handle->affinity()); + if (Cpu::threads() > 1 && m_thread->affinity() != -1L) { + Platform::setThreadAffinity(m_thread->affinity()); } - Platform::setThreadPriority(handle->priority()); - m_ctx = Mem::create(m_id); -} - - -Worker::~Worker() -{ + Platform::setThreadPriority(m_thread->priority()); } diff --git a/src/workers/Worker.h b/src/workers/Worker.h index 08a0551f..aad9e3c5 100644 --- a/src/workers/Worker.h +++ b/src/workers/Worker.h @@ -30,31 +30,40 @@ #include "interfaces/IWorker.h" +#include "Mem.h" struct cryptonight_ctx; class Handle; +namespace xmrig { + class CpuThread; +} + + class Worker : public IWorker { public: Worker(Handle *handle); - ~Worker(); + inline const MemInfo &memory() const { return m_memory; } + inline size_t id() const override { return m_id; } 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); } protected: void storeStats(); - cryptonight_ctx *m_ctx; - int m_id; - int m_threads; + const size_t m_id; + const size_t m_totalWays; + const uint32_t m_offset; + MemInfo m_memory; std::atomic m_hashCount; std::atomic m_timestamp; uint64_t m_count; uint64_t m_sequence; + xmrig::CpuThread *m_thread; }; diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp index f0aef448..8991966e 100644 --- a/src/workers/Workers.cpp +++ b/src/workers/Workers.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,21 @@ */ #include +#include #include "api/Api.h" +#include "common/log/Log.h" +#include "core/Config.h" +#include "core/Controller.h" +#include "crypto/CryptoNight_constants.h" #include "interfaces/IJobResultListener.h" +#include "interfaces/IThread.h" #include "Mem.h" -#include "Options.h" -#include "workers/DoubleWorker.h" +#include "rapidjson/document.h" #include "workers/Handle.h" #include "workers/Hashrate.h" -#include "workers/SingleWorker.h" +#include "workers/MultiWorker.h" #include "workers/Workers.h" @@ -40,6 +45,7 @@ bool Workers::m_enabled = true; Hashrate *Workers::m_hashrate = nullptr; IJobResultListener *Workers::m_listener = nullptr; Job Workers::m_job; +Workers::LaunchStatus Workers::m_status; std::atomic Workers::m_paused; std::atomic Workers::m_sequence; std::list Workers::m_queue; @@ -61,6 +67,26 @@ Job Workers::job() } +size_t Workers::hugePages() +{ + uv_mutex_lock(&m_mutex); + const size_t hugePages = m_status.hugePages; + uv_mutex_unlock(&m_mutex); + + return hugePages; +} + + +size_t Workers::threads() +{ + uv_mutex_lock(&m_mutex); + const size_t threads = m_status.threads; + uv_mutex_unlock(&m_mutex); + + return threads; +} + + void Workers::printHashrate(bool detail) { m_hashrate->print(); @@ -103,10 +129,18 @@ void Workers::setJob(const Job &job, bool donate) } -void Workers::start(int64_t affinity, int priority) +void Workers::start(xmrig::Controller *controller) { - const int threads = Mem::threads(); - m_hashrate = new Hashrate(threads); + const std::vector &threads = controller->config()->threads(); + m_status.algo = controller->config()->algorithm().algo(); + m_status.colors = controller->config()->isColors(); + m_status.threads = threads.size(); + + for (const xmrig::IThread *thread : threads) { + m_status.ways += thread->multiway(); + } + + m_hashrate = new Hashrate(threads.size(), controller); uv_mutex_init(&m_mutex); uv_rwlock_init(&m_rwlock); @@ -118,8 +152,12 @@ void Workers::start(int64_t affinity, int priority) uv_timer_init(uv_default_loop(), &m_timer); uv_timer_start(&m_timer, Workers::onTick, 500, 500); - for (int i = 0; i < threads; ++i) { - Handle *handle = new Handle(i, threads, affinity, priority); + uint32_t offset = 0; + + for (xmrig::IThread *thread : threads) { + Handle *handle = new Handle(thread, offset, m_status.ways); + offset += thread->multiway(); + m_workers.push_back(handle); handle->start(Workers::onReady); } @@ -151,17 +189,66 @@ void Workers::submit(const JobResult &result) } +#ifndef XMRIG_NO_API +void Workers::threadsSummary(rapidjson::Document &doc) +{ + uv_mutex_lock(&m_mutex); + const uint64_t pages[2] = { m_status.hugePages, m_status.pages }; + const uint64_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo); + uv_mutex_unlock(&m_mutex); + + auto &allocator = doc.GetAllocator(); + + rapidjson::Value hugepages(rapidjson::kArrayType); + hugepages.PushBack(pages[0], allocator); + hugepages.PushBack(pages[1], allocator); + + doc.AddMember("hugepages", hugepages, allocator); + doc.AddMember("memory", memory, allocator); +} +#endif + + void Workers::onReady(void *arg) { auto handle = static_cast(arg); - if (Mem::isDoubleHash()) { - handle->setWorker(new DoubleWorker(handle)); - } - else { - handle->setWorker(new SingleWorker(handle)); + + IWorker *worker = nullptr; + + switch (handle->config()->multiway()) { + case 1: + worker = new MultiWorker<1>(handle); + break; + + case 2: + worker = new MultiWorker<2>(handle); + break; + + case 3: + worker = new MultiWorker<3>(handle); + break; + + case 4: + worker = new MultiWorker<4>(handle); + break; + + case 5: + worker = new MultiWorker<5>(handle); + break; + + default: + break; } - handle->worker()->start(); + handle->setWorker(worker); + + if (!worker->selfTest()) { + LOG_ERR("thread %zu error: \"hash self-test failed\".", handle->worker()->id()); + + return; + } + + start(worker); } @@ -197,8 +284,35 @@ void Workers::onTick(uv_timer_t *handle) if ((m_ticks++ & 0xF) == 0) { m_hashrate->updateHighest(); } - -# ifndef XMRIG_NO_API - Api::tick(m_hashrate); -# endif +} + + +void Workers::start(IWorker *worker) +{ + const Worker *w = static_cast(worker); + + uv_mutex_lock(&m_mutex); + m_status.started++; + m_status.pages += w->memory().pages; + m_status.hugePages += w->memory().hugePages; + + if (m_status.started == m_status.threads) { + const double percent = (double) m_status.hugePages / m_status.pages * 100.0; + const size_t memory = m_status.ways * xmrig::cn_select_memory(m_status.algo) / 1048576; + + if (m_status.colors) { + LOG_INFO(GREEN_BOLD("READY (CPU)") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu.0 MB") "", + m_status.threads, m_status.ways, + (m_status.hugePages == m_status.pages ? "\x1B[1;32m" : (m_status.hugePages == 0 ? "\x1B[1;31m" : "\x1B[1;33m")), + m_status.hugePages, m_status.pages, percent, memory); + } + else { + LOG_INFO("READY (CPU) threads %zu(%zu) huge pages %zu/%zu %f%% memory %zu.0 MB", + m_status.threads, m_status.ways, m_status.hugePages, m_status.pages, percent, memory); + } + } + + uv_mutex_unlock(&m_mutex); + + worker->start(); } diff --git a/src/workers/Workers.h b/src/workers/Workers.h index 1c85089a..ca01e698 100644 --- a/src/workers/Workers.h +++ b/src/workers/Workers.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 @@ -30,43 +30,81 @@ #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 setEnabled(bool enabled); static void setJob(const Job &job, bool donate); - static void start(int64_t affinity, int priority); + static void start(xmrig::Controller *controller); static void stop(); static void submit(const JobResult &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 onTick(uv_timer_t *handle); + static void start(IWorker *worker); + + class LaunchStatus + { + public: + inline LaunchStatus() : + colors(true), + hugePages(0), + pages(0), + started(0), + threads(0), + ways(0), + algo(xmrig::CRYPTONIGHT) + {} + + bool colors; + size_t hugePages; + size_t pages; + size_t started; + size_t threads; + size_t ways; + xmrig::Algo algo; + }; static bool m_active; static bool m_enabled; static Hashrate *m_hashrate; static IJobResultListener *m_listener; static Job m_job; + static LaunchStatus m_status; static std::atomic m_paused; static std::atomic m_sequence; static std::list m_queue; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index b30cfb0b..00000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -project("xmrig-test" C) -cmake_minimum_required(VERSION 3.0) - -include(CTest) - -add_subdirectory(unity) -add_subdirectory(cryptonight) -add_subdirectory(cryptonight_lite) -add_subdirectory(autoconf) \ No newline at end of file diff --git a/test/autoconf/CMakeLists.txt b/test/autoconf/CMakeLists.txt deleted file mode 100644 index b956a9de..00000000 --- a/test/autoconf/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(SOURCES - autoconf.c - ../../cpu.h - ../../cpu.c - ) - -add_executable(autoconf_app ${SOURCES}) -target_link_libraries(autoconf_app unity) - -include_directories(../..) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") -add_definitions(-DBUILD_TEST) - -add_test(autoconf_test autoconf_app) diff --git a/test/autoconf/autoconf.c b/test/autoconf/autoconf.c deleted file mode 100644 index 86ced5f0..00000000 --- a/test/autoconf/autoconf.c +++ /dev/null @@ -1,152 +0,0 @@ -#include - -#include "cpu.h" -#include "options.h" - -struct cpu_info cpu_info = { 0 }; - - -static void set_cpu_info(int total_logical_cpus, int l2_cache, int l3_cache) { - cpu_info.total_cores = total_logical_cpus; - cpu_info.total_logical_cpus = total_logical_cpus; - cpu_info.l2_cache = l2_cache; - cpu_info.l3_cache = l3_cache; -} - - -void test_autoconf_should_GetOptimalThreadsCounti7(void) { - set_cpu_info(8, 1024, 8192); // 4C/8T 8 MB (Generic i7 CPU) - - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(5, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 60)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 50)); - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 35)); - TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 20)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 5)); -} - - -void test_autoconf_should_GetOptimalThreadsCounti5(void) { - set_cpu_info(4, 1024, 6144); // 2C/4T 6 MB (Generic i5 CPU) - - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75)); - - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75)); -} - - -void test_autoconf_should_GetOptimalThreadsCounti3(void) { - set_cpu_info(4, 512, 3072); // 2C/4T 3 MB (Generic i3 CPU) - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75)); - - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75)); -} - - -void test_autoconf_should_GetOptimalThreadsCountR7(void) { - set_cpu_info(16, 4096, 16384); // 8C/16T 16 MB (AMD Ryzen 7) - - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75)); - - TEST_ASSERT_EQUAL_INT(16, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75)); -} - - -void test_autoconf_should_GetOptimalThreadsCountTwoE5620(void) { - set_cpu_info(16, 2048, 24576); // 8C/16T 24 MB (Two E5620) - - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75)); - TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75)); - - TEST_ASSERT_EQUAL_INT(16, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(12, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75)); -} - - -void test_autoconf_should_GetOptimalThreadsCountVCPU(void) { - set_cpu_info(1, 1024, 15360); // 1C/1T 15 MB (Single core Virtual CPU) - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 75)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 75)); - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 75)); -} - - -void test_autoconf_should_GetOptimalThreadsCountNoL3(void) { - set_cpu_info(8, 8192, 0); // 4C/8T (Multi core Virtual CPU without L3 cache) - - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT, false, 100)); - TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT, true, 100)); - - TEST_ASSERT_EQUAL_INT(8, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 100)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, true, 100)); - - TEST_ASSERT_EQUAL_INT(6, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 75)); - TEST_ASSERT_EQUAL_INT(5, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 60)); - TEST_ASSERT_EQUAL_INT(4, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 50)); - TEST_ASSERT_EQUAL_INT(3, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 35)); - TEST_ASSERT_EQUAL_INT(2, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 20)); - TEST_ASSERT_EQUAL_INT(1, get_optimal_threads_count(ALGO_CRYPTONIGHT_LITE, false, 5)); -} - - -int main(void) -{ - UNITY_BEGIN(); - - RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti7); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti5); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCounti3); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCountR7); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCountR7); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCountTwoE5620); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCountVCPU); - RUN_TEST(test_autoconf_should_GetOptimalThreadsCountNoL3); - - return UNITY_END(); -} diff --git a/test/cryptonight/CMakeLists.txt b/test/cryptonight/CMakeLists.txt deleted file mode 100644 index 4ebbbcc9..00000000 --- a/test/cryptonight/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -set(SOURCES - cryptonight.c - ../../options.h - ../../algo/cryptonight/cryptonight.h - ../../algo/cryptonight/cryptonight.c - ../../algo/cryptonight/cryptonight_av1_aesni.c - ../../algo/cryptonight/cryptonight_av2_aesni_double.c - ../../algo/cryptonight/cryptonight_av3_softaes.c - ../../algo/cryptonight/cryptonight_av4_softaes_double.c - ../../crypto/c_keccak.c - ../../crypto/c_blake256.c - ../../crypto/c_groestl.c - ../../crypto/c_jh.c - ../../crypto/c_skein.c - ../../crypto/soft_aes.c - ) - -add_executable(cryptonight_app ${SOURCES}) -target_link_libraries(cryptonight_app unity) - -include_directories(../..) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -fno-strict-aliasing") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") -add_definitions(-DBUILD_TEST) -add_definitions(-DXMRIG_NO_AEON) - -add_test(cryptonight_test cryptonight_app) diff --git a/test/cryptonight/cryptonight.c b/test/cryptonight/cryptonight.c deleted file mode 100644 index bcc0db30..00000000 --- a/test/cryptonight/cryptonight.c +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include - -#include "options.h" -#include "algo/cryptonight/cryptonight.h" - -bool opt_double_hash = false; - -const static char input1[152] = { - 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, -}; - -const static char input2[] = "This is a test"; -const static char input3[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus pellentesque metus."; - - -void cryptonight_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); - - -static char hash[64]; -#define RESULT1 "1a3ffbee909b420d91f7be6e5fb56db71b3110d886011e877ee5786afd080100" -#define RESULT1_DOUBLE "1a3ffbee909b420d91f7be6e5fb56db71b3110d886011e877ee5786afd0801001b606a3f4a07d6489a1bcd07697bd16696b61c8ae982f61a90160f4e52828a7f" -#define RESULT2 "a084f01d1437a09c6985401b60d43554ae105802c5f5d8a9b3253649c0be6605" -#define RESULT3 "0bbe54bd26caa92a1d436eec71cbef02560062fa689fe14d7efcf42566b411cf" - - -static char *bin2hex(const unsigned char *p, size_t len) -{ - char *s = malloc((len * 2) + 1); - if (!s) { - return NULL; - } - - for (int i = 0; i < len; i++) { - sprintf(s + (i * 2), "%02x", (unsigned int) p[i]); - } - - return s; -} - - -static void * create_ctx(int ratio) { - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16); - ctx->memory = (uint8_t *) _mm_malloc(MEMORY * ratio, 16); - - return ctx; -} - - -static void free_ctx(struct cryptonight_ctx *ctx) { - _mm_free(ctx->memory); - _mm_free(ctx); -} - - -void test_cryptonight_av1_should_CalcHash(void) { - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(1); - - cryptonight_av1_aesni(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1, bin2hex(hash, 32)); - - cryptonight_av1_aesni(input2, strlen(input2), &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT2, bin2hex(hash, 32)); - - cryptonight_av1_aesni(input3, strlen(input3), &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT3, bin2hex(hash, 32)); - - free_ctx(ctx); -} - - -void test_cryptonight_av2_should_CalcHash(void) -{ - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(2); - - cryptonight_av2_aesni_double(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1_DOUBLE, bin2hex(hash, 64)); - - free_ctx(ctx); -} - - -void test_cryptonight_av3_should_CalcHash(void) -{ - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(1); - - cryptonight_av3_softaes(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1, bin2hex(hash, 32)); - - cryptonight_av3_softaes(input2, strlen(input2), &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT2, bin2hex(hash, 32)); - - cryptonight_av3_softaes(input3, strlen(input3), &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT3, bin2hex(hash, 32)); - - free_ctx(ctx); -} - - -void test_cryptonight_av4_should_CalcHash(void) -{ - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(2); - - cryptonight_av4_softaes_double(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1_DOUBLE, bin2hex(hash, 64)); - - free_ctx(ctx); -} - - -int main(void) -{ - UNITY_BEGIN(); - - RUN_TEST(test_cryptonight_av1_should_CalcHash); - RUN_TEST(test_cryptonight_av2_should_CalcHash); - RUN_TEST(test_cryptonight_av3_should_CalcHash); - RUN_TEST(test_cryptonight_av4_should_CalcHash); - - return UNITY_END(); -} diff --git a/test/cryptonight_lite/CMakeLists.txt b/test/cryptonight_lite/CMakeLists.txt deleted file mode 100644 index 9a83ecbc..00000000 --- a/test/cryptonight_lite/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -set(SOURCES - cryptonight_lite.c - ../../options.h - ../../algo/cryptonight/cryptonight.h - ../../algo/cryptonight/cryptonight.c - ../../algo/cryptonight-lite/cryptonight_lite_av1_aesni.c - ../../algo/cryptonight-lite/cryptonight_lite_av2_aesni_double.c - ../../algo/cryptonight-lite/cryptonight_lite_av3_softaes.c - ../../algo/cryptonight-lite/cryptonight_lite_av4_softaes_double.c - ../../crypto/c_keccak.c - ../../crypto/c_blake256.c - ../../crypto/c_groestl.c - ../../crypto/c_jh.c - ../../crypto/c_skein.c - ../../crypto/soft_aes.c - ) - -add_executable(cryptonight_lite_app ${SOURCES}) -target_link_libraries(cryptonight_lite_app unity) - -include_directories(../..) - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -fno-strict-aliasing") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") -add_definitions(-DBUILD_TEST) - -add_test(cryptonight_lite_test cryptonight_lite_app) diff --git a/test/cryptonight_lite/cryptonight_lite.c b/test/cryptonight_lite/cryptonight_lite.c deleted file mode 100644 index a6d5b554..00000000 --- a/test/cryptonight_lite/cryptonight_lite.c +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include - -#include "options.h" -#include "algo/cryptonight/cryptonight.h" - -bool opt_double_hash = false; -enum mining_algo opt_algo = ALGO_CRYPTONIGHT_LITE; - -const static char input1[152] = { - 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, -}; - - -void cryptonight_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx) {} -void cryptonight_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx) {} -void cryptonight_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx) {} -void cryptonight_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx) {} - -void cryptonight_lite_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_lite_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_lite_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); -void cryptonight_lite_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx); - - -static char hash[64]; -#define RESULT1 "3695b4b53bb00358b0ad38dc160feb9e004eece09b83a72ef6ba9864d3510c88" -#define RESULT1_DOUBLE "3695b4b53bb00358b0ad38dc160feb9e004eece09b83a72ef6ba9864d3510c8828a22bad3f93d1408fca472eb5ad1cbe75f21d053c8ce5b3af105a57713e21dd" - - -static char *bin2hex(const unsigned char *p, size_t len) -{ - char *s = malloc((len * 2) + 1); - if (!s) { - return NULL; - } - - for (int i = 0; i < len; i++) { - sprintf(s + (i * 2), "%02x", (unsigned int) p[i]); - } - - return s; -} - - -static void * create_ctx(int ratio) { - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16); - ctx->memory = (uint8_t *) _mm_malloc(MEMORY_LITE * ratio, 16); - - return ctx; -} - - -static void free_ctx(struct cryptonight_ctx *ctx) { - _mm_free(ctx->memory); - _mm_free(ctx); -} - - -void test_cryptonight_lite_av1_should_CalcHash(void) { - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(1); - - cryptonight_lite_av1_aesni(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1, bin2hex(hash, 32)); - - free_ctx(ctx); -} - - -void test_cryptonight_lite_av2_should_CalcHash(void) -{ - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(2); - - cryptonight_lite_av2_aesni_double(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1_DOUBLE, bin2hex(hash, 64)); - - free_ctx(ctx); -} - - -void test_cryptonight_lite_av3_should_CalcHash(void) { - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(1); - - cryptonight_lite_av3_softaes(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1, bin2hex(hash, 32)); - - free_ctx(ctx); -} - - -void test_cryptonight_lite_av4_should_CalcHash(void) -{ - struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) create_ctx(2); - - cryptonight_lite_av4_softaes_double(input1, 76, &hash, ctx); - TEST_ASSERT_EQUAL_STRING(RESULT1_DOUBLE, bin2hex(hash, 64)); - - free_ctx(ctx); -} - - -int main(void) -{ - UNITY_BEGIN(); - - RUN_TEST(test_cryptonight_lite_av1_should_CalcHash); - RUN_TEST(test_cryptonight_lite_av2_should_CalcHash); - RUN_TEST(test_cryptonight_lite_av3_should_CalcHash); - RUN_TEST(test_cryptonight_lite_av4_should_CalcHash); - - return UNITY_END(); -} diff --git a/test/unity/CMakeLists.txt b/test/unity/CMakeLists.txt deleted file mode 100644 index 6e350179..00000000 --- a/test/unity/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_library(unity STATIC unity.c) -target_include_directories(unity PUBLIC .) diff --git a/test/unity/unity.c b/test/unity/unity.c deleted file mode 100644 index a43e33e1..00000000 --- a/test/unity/unity.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* ========================================================================= - Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -============================================================================ */ - -#include "unity.h" -#include - -/* If omitted from header, declare overrideable prototypes here so they're ready for use */ -#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION -void UNITY_OUTPUT_CHAR(int); -#endif - -/* Helpful macros for us to use here */ -#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; longjmp(Unity.AbortFrame, 1); } -#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; longjmp(Unity.AbortFrame, 1); } - -/* return prematurely if we are already in failure or ignore state */ -#define UNITY_SKIP_EXECUTION { if ((Unity.CurrentTestFailed != 0) || (Unity.CurrentTestIgnored != 0)) {return;} } - -struct _Unity Unity; - -static const char UnityStrOk[] = "OK"; -static const char UnityStrPass[] = "PASS"; -static const char UnityStrFail[] = "FAIL"; -static const char UnityStrIgnore[] = "IGNORE"; -static const char UnityStrNull[] = "NULL"; -static const char UnityStrSpacer[] = ". "; -static const char UnityStrExpected[] = " Expected "; -static const char UnityStrWas[] = " Was "; -static const char UnityStrElement[] = " Element "; -static const char UnityStrByte[] = " Byte "; -static const char UnityStrMemory[] = " Memory Mismatch."; -static const char UnityStrDelta[] = " Values Not Within Delta "; -static const char UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; -static const char UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; -static const char UnityStrNullPointerForActual[] = " Actual pointer was NULL"; -#ifndef UNITY_EXCLUDE_FLOAT -static const char UnityStrNot[] = "Not "; -static const char UnityStrInf[] = "Infinity"; -static const char UnityStrNegInf[] = "Negative Infinity"; -static const char UnityStrNaN[] = "NaN"; -static const char UnityStrDet[] = "Determinate"; -static const char UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; -#endif -const char UnityStrErrFloat[] = "Unity Floating Point Disabled"; -const char UnityStrErrDouble[] = "Unity Double Precision Disabled"; -const char UnityStrErr64[] = "Unity 64-bit Support Disabled"; -static const char UnityStrBreaker[] = "-----------------------"; -static const char UnityStrResultsTests[] = " Tests "; -static const char UnityStrResultsFailures[] = " Failures "; -static const char UnityStrResultsIgnored[] = " Ignored "; -static const char UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; -static const char UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; - -/* compiler-generic print formatting masks */ -static const _U_UINT UnitySizeMask[] = -{ - 255u, /* 0xFF */ - 65535u, /* 0xFFFF */ - 65535u, - 4294967295u, /* 0xFFFFFFFF */ - 4294967295u, - 4294967295u, - 4294967295u -#ifdef UNITY_SUPPORT_64 - ,0xFFFFFFFFFFFFFFFF -#endif -}; - -/*----------------------------------------------- - * Pretty Printers & Test Result Output Handlers - *-----------------------------------------------*/ - -void UnityPrint(const char* string) -{ - const char* pch = string; - - if (pch != NULL) - { - while (*pch) - { - /* printable characters plus CR & LF are printed */ - if ((*pch <= 126) && (*pch >= 32)) - { - UNITY_OUTPUT_CHAR(*pch); - } - /* write escaped carriage returns */ - else if (*pch == 13) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('r'); - } - /* write escaped line feeds */ - else if (*pch == 10) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('n'); - } - /* unprintable characters are shown as codes */ - else - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((_U_UINT)*pch, 2); - } - pch++; - } - } -} - -void UnityPrintLen(const char* string, const _UU32 length); -void UnityPrintLen(const char* string, const _UU32 length) -{ - const char* pch = string; - - if (pch != NULL) - { - while (*pch && (_UU32)(pch - string) < length) - { - /* printable characters plus CR & LF are printed */ - if ((*pch <= 126) && (*pch >= 32)) - { - UNITY_OUTPUT_CHAR(*pch); - } - /* write escaped carriage returns */ - else if (*pch == 13) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('r'); - } - /* write escaped line feeds */ - else if (*pch == 10) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('n'); - } - /* unprintable characters are shown as codes */ - else - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((_U_UINT)*pch, 2); - } - pch++; - } - } -} - -/*-----------------------------------------------*/ -void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style) -{ - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - UnityPrintNumber(number); - } - else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) - { - UnityPrintNumberUnsigned( (_U_UINT)number & UnitySizeMask[((_U_UINT)style & (_U_UINT)0x0F) - 1] ); - } - else - { - UNITY_OUTPUT_CHAR('0'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((_U_UINT)number, (char)((style & 0x000F) << 1)); - } -} - -/*-----------------------------------------------*/ -void UnityPrintNumber(const _U_SINT number_to_print) -{ - _U_UINT number = (_U_UINT)number_to_print; - - if (number_to_print < 0) - { - /* A negative number, including MIN negative */ - UNITY_OUTPUT_CHAR('-'); - number = (_U_UINT)(-number_to_print); - } - UnityPrintNumberUnsigned(number); -} - -/*----------------------------------------------- - * basically do an itoa using as little ram as possible */ -void UnityPrintNumberUnsigned(const _U_UINT number) -{ - _U_UINT divisor = 1; - - /* figure out initial divisor */ - while (number / divisor > 9) - { - divisor *= 10; - } - - /* now mod and print, then divide divisor */ - do - { - UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); - divisor /= 10; - } - while (divisor > 0); -} - -/*-----------------------------------------------*/ -void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print) -{ - _U_UINT nibble; - char nibbles = nibbles_to_print; - - while (nibbles > 0) - { - nibble = (number >> (--nibbles << 2)) & 0x0000000F; - if (nibble <= 9) - { - UNITY_OUTPUT_CHAR((char)('0' + nibble)); - } - else - { - UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); - } - } -} - -/*-----------------------------------------------*/ -void UnityPrintMask(const _U_UINT mask, const _U_UINT number) -{ - _U_UINT current_bit = (_U_UINT)1 << (UNITY_INT_WIDTH - 1); - _US32 i; - - for (i = 0; i < UNITY_INT_WIDTH; i++) - { - if (current_bit & mask) - { - if (current_bit & number) - { - UNITY_OUTPUT_CHAR('1'); - } - else - { - UNITY_OUTPUT_CHAR('0'); - } - } - else - { - UNITY_OUTPUT_CHAR('X'); - } - current_bit = current_bit >> 1; - } -} - -/*-----------------------------------------------*/ -#ifdef UNITY_FLOAT_VERBOSE -#include - -#ifndef UNITY_VERBOSE_NUMBER_MAX_LENGTH -# ifdef UNITY_DOUBLE_VERBOSE -# define UNITY_VERBOSE_NUMBER_MAX_LENGTH 317 -# else -# define UNITY_VERBOSE_NUMBER_MAX_LENGTH 47 -# endif -#endif - -void UnityPrintFloat(_UD number) -{ - char TempBuffer[UNITY_VERBOSE_NUMBER_MAX_LENGTH + 1]; - snprintf(TempBuffer, sizeof(TempBuffer), "%.6f", number); - UnityPrint(TempBuffer); -} -#endif - -/*-----------------------------------------------*/ - -void UnityPrintFail(void); -void UnityPrintFail(void) -{ - UnityPrint(UnityStrFail); -} - -void UnityPrintOk(void); -void UnityPrintOk(void) -{ - UnityPrint(UnityStrOk); -} - -/*-----------------------------------------------*/ -static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line); -static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) -{ -#ifndef UNITY_FIXTURES - UnityPrint(file); - UNITY_OUTPUT_CHAR(':'); - UnityPrintNumber((_U_SINT)line); - UNITY_OUTPUT_CHAR(':'); - UnityPrint(Unity.CurrentTestName); - UNITY_OUTPUT_CHAR(':'); -#else - UNITY_UNUSED(file); - UNITY_UNUSED(line); -#endif -} - -/*-----------------------------------------------*/ -static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line); -static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) -{ -#ifndef UNITY_FIXTURES - UnityTestResultsBegin(Unity.TestFile, line); -#else - UNITY_UNUSED(line); -#endif - UnityPrint(UnityStrFail); - UNITY_OUTPUT_CHAR(':'); -} - -/*-----------------------------------------------*/ -void UnityConcludeTest(void) -{ - if (Unity.CurrentTestIgnored) - { - Unity.TestIgnores++; - } - else if (!Unity.CurrentTestFailed) - { - UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); - UnityPrint(UnityStrPass); - } - else - { - Unity.TestFailures++; - } - - Unity.CurrentTestFailed = 0; - Unity.CurrentTestIgnored = 0; - UNITY_PRINT_EOL(); - UNITY_FLUSH_CALL(); -} - -/*-----------------------------------------------*/ -static void UnityAddMsgIfSpecified(const char* msg); -static void UnityAddMsgIfSpecified(const char* msg) -{ - if (msg) - { - UnityPrint(UnityStrSpacer); -#ifndef UNITY_EXCLUDE_DETAILS - if (Unity.CurrentDetail1) - { - UnityPrint(UnityStrDetail1Name); - UnityPrint(Unity.CurrentDetail1); - if (Unity.CurrentDetail2) - { - UnityPrint(UnityStrDetail2Name); - UnityPrint(Unity.CurrentDetail2); - } - UnityPrint(UnityStrSpacer); - } -#endif - UnityPrint(msg); - } -} - -/*-----------------------------------------------*/ -static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual); -static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) -{ - UnityPrint(UnityStrExpected); - if (expected != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrint(expected); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } - UnityPrint(UnityStrWas); - if (actual != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrint(actual); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } -} - -/*-----------------------------------------------*/ -static void UnityPrintExpectedAndActualStringsLen(const char* expected, const char* actual, const _UU32 length) -{ - UnityPrint(UnityStrExpected); - if (expected != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrintLen(expected, length); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } - UnityPrint(UnityStrWas); - if (actual != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrintLen(actual, length); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } -} - - - -/*----------------------------------------------- - * Assertion & Control Helpers - *-----------------------------------------------*/ - -static int UnityCheckArraysForNull(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_LINE_TYPE lineNumber, const char* msg) -{ - /* return true if they are both NULL */ - if ((expected == NULL) && (actual == NULL)) - return 1; - - /* throw error if just expected is NULL */ - if (expected == NULL) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrNullPointerForExpected); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - - /* throw error if just actual is NULL */ - if (actual == NULL) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrNullPointerForActual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - - /* return false if neither is NULL */ - return 0; -} - -/*----------------------------------------------- - * Assertion Functions - *-----------------------------------------------*/ - -void UnityAssertBits(const _U_SINT mask, - const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_SKIP_EXECUTION; - - if ((mask & expected) != (mask & actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintMask((_U_UINT)mask, (_U_UINT)expected); - UnityPrint(UnityStrWas); - UnityPrintMask((_U_UINT)mask, (_U_UINT)actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualNumber(const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - UNITY_SKIP_EXECUTION; - - if (expected != actual) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expected, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -#define UnityPrintPointlessAndBail() \ -{ \ - UnityTestResultsFailBegin(lineNumber); \ - UnityPrint(UnityStrPointless); \ - UnityAddMsgIfSpecified(msg); \ - UNITY_FAIL_AND_BAIL; } - -/*-----------------------------------------------*/ -void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - _UU32 elements = num_elements; - UNITY_INTERNAL_PTR ptr_exp = (UNITY_INTERNAL_PTR)expected; - UNITY_INTERNAL_PTR ptr_act = (UNITY_INTERNAL_PTR)actual; - - UNITY_SKIP_EXECUTION; - - if (elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) - return; - - /* If style is UNITY_DISPLAY_STYLE_INT, we'll fall into the default case rather than the INT16 or INT32 (etc) case - * as UNITY_DISPLAY_STYLE_INT includes a flag for UNITY_DISPLAY_RANGE_AUTO, which the width-specific - * variants do not. Therefore remove this flag. */ - switch(style & (UNITY_DISPLAY_STYLE_T)(~UNITY_DISPLAY_RANGE_AUTO)) - { - case UNITY_DISPLAY_STYLE_HEX8: - case UNITY_DISPLAY_STYLE_INT8: - case UNITY_DISPLAY_STYLE_UINT8: - while (elements--) - { - if (*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1); - ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1); - } - break; - case UNITY_DISPLAY_STYLE_HEX16: - case UNITY_DISPLAY_STYLE_INT16: - case UNITY_DISPLAY_STYLE_UINT16: - while (elements--) - { - if (*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 2); - ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 2); - } - break; -#ifdef UNITY_SUPPORT_64 - case UNITY_DISPLAY_STYLE_HEX64: - case UNITY_DISPLAY_STYLE_INT64: - case UNITY_DISPLAY_STYLE_UINT64: - while (elements--) - { - if (*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 8); - ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 8); - } - break; -#endif - default: - while (elements--) - { - if (*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 4); - ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 4); - } - break; - } -} - -/*-----------------------------------------------*/ -/* Wrap this define in a function with variable types as float or double */ -#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ - if (isinf(expected) && isinf(actual) && (isneg(expected) == isneg(actual))) return 1; \ - if (isnan(expected) && isnan(actual)) return 1; \ - diff = actual - expected; \ - if (diff < 0.0f) diff = 0.0f - diff; \ - if (delta < 0.0f) delta = 0.0f - delta; \ - return !(isnan(diff) || isinf(diff) || (delta < diff)); - /* This first part of this condition will catch any NaN or Infinite values */ - -#ifndef UNITY_EXCLUDE_FLOAT -static int UnityFloatsWithin(_UF delta, _UF expected, _UF actual) -{ - _UF diff; - UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); -} - -void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, - UNITY_PTR_ATTRIBUTE const _UF* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 elements = num_elements; - UNITY_PTR_ATTRIBUTE const _UF* ptr_expected = expected; - UNITY_PTR_ATTRIBUTE const _UF* ptr_actual = actual; - - UNITY_SKIP_EXECUTION; - - if (elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) - return; - - while (elements--) - { - if (!UnityFloatsWithin(*ptr_expected * UNITY_FLOAT_PRECISION, *ptr_expected, *ptr_actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); -#ifdef UNITY_FLOAT_VERBOSE - UnityPrint(UnityStrExpected); - UnityPrintFloat(*ptr_expected); - UnityPrint(UnityStrWas); - UnityPrintFloat(*ptr_actual); -#else - UnityPrint(UnityStrDelta); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_expected++; - ptr_actual++; - } -} - -/*-----------------------------------------------*/ -void UnityAssertFloatsWithin(const _UF delta, - const _UF expected, - const _UF actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_SKIP_EXECUTION; - - - if (!UnityFloatsWithin(delta, expected, actual)) - { - UnityTestResultsFailBegin(lineNumber); -#ifdef UNITY_FLOAT_VERBOSE - UnityPrint(UnityStrExpected); - UnityPrintFloat(expected); - UnityPrint(UnityStrWas); - UnityPrintFloat(actual); -#else - UnityPrint(UnityStrDelta); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertFloatSpecial(const _UF actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style) -{ - const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; - _U_SINT should_be_trait = ((_U_SINT)style & 1); - _U_SINT is_trait = !should_be_trait; - _U_SINT trait_index = (_U_SINT)(style >> 1); - - UNITY_SKIP_EXECUTION; - - switch(style) - { - case UNITY_FLOAT_IS_INF: - case UNITY_FLOAT_IS_NOT_INF: - is_trait = isinf(actual) & ispos(actual); - break; - case UNITY_FLOAT_IS_NEG_INF: - case UNITY_FLOAT_IS_NOT_NEG_INF: - is_trait = isinf(actual) & isneg(actual); - break; - - case UNITY_FLOAT_IS_NAN: - case UNITY_FLOAT_IS_NOT_NAN: - is_trait = isnan(actual); - break; - - /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */ - case UNITY_FLOAT_IS_DET: - case UNITY_FLOAT_IS_NOT_DET: - if (isinf(actual) | isnan(actual)) - is_trait = 0; - else - is_trait = 1; - break; - - default: - trait_index = 0; - trait_names[0] = UnityStrInvalidFloatTrait; - break; - } - - if (is_trait != should_be_trait) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - if (!should_be_trait) - UnityPrint(UnityStrNot); - UnityPrint(trait_names[trait_index]); - UnityPrint(UnityStrWas); -#ifdef UNITY_FLOAT_VERBOSE - UnityPrintFloat(actual); -#else - if (should_be_trait) - UnityPrint(UnityStrNot); - UnityPrint(trait_names[trait_index]); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -#endif /* not UNITY_EXCLUDE_FLOAT */ - -/*-----------------------------------------------*/ -#ifndef UNITY_EXCLUDE_DOUBLE -static int UnityDoublesWithin(_UD delta, _UD expected, _UD actual) -{ - _UD diff; - UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); -} - -void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, - UNITY_PTR_ATTRIBUTE const _UD* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 elements = num_elements; - UNITY_PTR_ATTRIBUTE const _UD* ptr_expected = expected; - UNITY_PTR_ATTRIBUTE const _UD* ptr_actual = actual; - - UNITY_SKIP_EXECUTION; - - if (elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) - return; - - while (elements--) - { - if (!UnityDoublesWithin(*ptr_expected * UNITY_DOUBLE_PRECISION, *ptr_expected, *ptr_actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); -#ifdef UNITY_DOUBLE_VERBOSE - UnityPrint(UnityStrExpected); - UnityPrintFloat((float)(*ptr_expected)); - UnityPrint(UnityStrWas); - UnityPrintFloat((float)(*ptr_actual)); -#else - UnityPrint(UnityStrDelta); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_expected++; - ptr_actual++; - } -} - -/*-----------------------------------------------*/ -void UnityAssertDoublesWithin(const _UD delta, - const _UD expected, - const _UD actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_SKIP_EXECUTION; - - if (!UnityDoublesWithin(delta, expected, actual)) - { - UnityTestResultsFailBegin(lineNumber); -#ifdef UNITY_DOUBLE_VERBOSE - UnityPrint(UnityStrExpected); - UnityPrintFloat((float)expected); - UnityPrint(UnityStrWas); - UnityPrintFloat((float)actual); -#else - UnityPrint(UnityStrDelta); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ - -void UnityAssertDoubleSpecial(const _UD actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style) -{ - const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; - _U_SINT should_be_trait = ((_U_SINT)style & 1); - _U_SINT is_trait = !should_be_trait; - _U_SINT trait_index = (_U_SINT)(style >> 1); - - UNITY_SKIP_EXECUTION; - - switch(style) - { - case UNITY_FLOAT_IS_INF: - case UNITY_FLOAT_IS_NOT_INF: - is_trait = isinf(actual) & ispos(actual); - break; - case UNITY_FLOAT_IS_NEG_INF: - case UNITY_FLOAT_IS_NOT_NEG_INF: - is_trait = isinf(actual) & isneg(actual); - break; - - case UNITY_FLOAT_IS_NAN: - case UNITY_FLOAT_IS_NOT_NAN: - is_trait = isnan(actual); - break; - - /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */ - case UNITY_FLOAT_IS_DET: - case UNITY_FLOAT_IS_NOT_DET: - if (isinf(actual) | isnan(actual)) - is_trait = 0; - else - is_trait = 1; - break; - - default: - trait_index = 0; - trait_names[0] = UnityStrInvalidFloatTrait; - break; - } - - if (is_trait != should_be_trait) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - if (!should_be_trait) - UnityPrint(UnityStrNot); - UnityPrint(trait_names[trait_index]); - UnityPrint(UnityStrWas); -#ifdef UNITY_DOUBLE_VERBOSE - UnityPrintFloat(actual); -#else - if (should_be_trait) - UnityPrint(UnityStrNot); - UnityPrint(trait_names[trait_index]); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - - -#endif /* not UNITY_EXCLUDE_DOUBLE */ - -/*-----------------------------------------------*/ -void UnityAssertNumbersWithin( const _U_UINT delta, - const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - UNITY_SKIP_EXECUTION; - - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - if (actual > expected) - Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta); - else - Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta); - } - else - { - if ((_U_UINT)actual > (_U_UINT)expected) - Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta); - else - Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta); - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrDelta); - UnityPrintNumberByStyle((_U_SINT)delta, style); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expected, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualString(const char* expected, - const char* actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 i; - - UNITY_SKIP_EXECUTION; - - /* if both pointers not null compare the strings */ - if (expected && actual) - { - for (i = 0; expected[i] || actual[i]; i++) - { - if (expected[i] != actual[i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrintExpectedAndActualStrings(expected, actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualStringLen(const char* expected, - const char* actual, - const _UU32 length, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 i; - - UNITY_SKIP_EXECUTION; - - /* if both pointers not null compare the strings */ - if (expected && actual) - { - for (i = 0; (i < length) && (expected[i] || actual[i]); i++) - { - if (expected[i] != actual[i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrintExpectedAndActualStringsLen(expected, actual, length); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - - -/*-----------------------------------------------*/ -void UnityAssertEqualStringArray( const char** expected, - const char** actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 i, j = 0; - - UNITY_SKIP_EXECUTION; - - /* if no elements, it's an error */ - if (num_elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) - return; - - do - { - /* if both pointers not null compare the strings */ - if (expected[j] && actual[j]) - { - for (i = 0; expected[j][i] || actual[j][i]; i++) - { - if (expected[j][i] != actual[j][i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected[j] != actual[j]) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - if (num_elements > 1) - { - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(j); - } - UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j])); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - } while (++j < num_elements); -} - -/*-----------------------------------------------*/ -void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const _UU32 length, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; - UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual; - _UU32 elements = num_elements; - _UU32 bytes; - - UNITY_SKIP_EXECUTION; - - if ((elements == 0) || (length == 0)) - { - UnityPrintPointlessAndBail(); - } - - if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) - return; - - while (elements--) - { - bytes = length; - while (bytes--) - { - if (*ptr_exp != *ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrMemory); - if (num_elements > 1) - { - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - } - UnityPrint(UnityStrByte); - UnityPrintNumberUnsigned(length - bytes - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1); - ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1); - } - } -} - -/*----------------------------------------------- - * Control Functions - *-----------------------------------------------*/ - -void UnityFail(const char* msg, const UNITY_LINE_TYPE line) -{ - UNITY_SKIP_EXECUTION; - - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrintFail(); - if (msg != NULL) - { - UNITY_OUTPUT_CHAR(':'); - -#ifndef UNITY_EXCLUDE_DETAILS - if (Unity.CurrentDetail1) - { - UnityPrint(UnityStrDetail1Name); - UnityPrint(Unity.CurrentDetail1); - if (Unity.CurrentDetail2) - { - UnityPrint(UnityStrDetail2Name); - UnityPrint(Unity.CurrentDetail2); - } - UnityPrint(UnityStrSpacer); - } -#endif - if (msg[0] != ' ') - { - UNITY_OUTPUT_CHAR(' '); - } - UnityPrint(msg); - } - - UNITY_FAIL_AND_BAIL; -} - -/*-----------------------------------------------*/ -void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) -{ - UNITY_SKIP_EXECUTION; - - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint(UnityStrIgnore); - if (msg != NULL) - { - UNITY_OUTPUT_CHAR(':'); - UNITY_OUTPUT_CHAR(' '); - UnityPrint(msg); - } - UNITY_IGNORE_AND_BAIL; -} - -/*-----------------------------------------------*/ -#if defined(UNITY_WEAK_ATTRIBUTE) - UNITY_WEAK_ATTRIBUTE void setUp(void) { } - UNITY_WEAK_ATTRIBUTE void tearDown(void) { } -#elif defined(UNITY_WEAK_PRAGMA) -# pragma weak setUp - void setUp(void) { } -# pragma weak tearDown - void tearDown(void) { } -#endif -/*-----------------------------------------------*/ -void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) -{ - Unity.CurrentTestName = FuncName; - Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; - Unity.NumberOfTests++; - UNITY_CLR_DETAILS(); - if (TEST_PROTECT()) - { - setUp(); - Func(); - } - if (TEST_PROTECT() && !(Unity.CurrentTestIgnored)) - { - tearDown(); - } - UnityConcludeTest(); -} - -/*-----------------------------------------------*/ -void UnityBegin(const char* filename) -{ - Unity.TestFile = filename; - Unity.CurrentTestName = NULL; - Unity.CurrentTestLineNumber = 0; - Unity.NumberOfTests = 0; - Unity.TestFailures = 0; - Unity.TestIgnores = 0; - Unity.CurrentTestFailed = 0; - Unity.CurrentTestIgnored = 0; - - UNITY_CLR_DETAILS(); - UNITY_OUTPUT_START(); -} - -/*-----------------------------------------------*/ -int UnityEnd(void) -{ - UNITY_PRINT_EOL(); - UnityPrint(UnityStrBreaker); - UNITY_PRINT_EOL(); - UnityPrintNumber((_U_SINT)(Unity.NumberOfTests)); - UnityPrint(UnityStrResultsTests); - UnityPrintNumber((_U_SINT)(Unity.TestFailures)); - UnityPrint(UnityStrResultsFailures); - UnityPrintNumber((_U_SINT)(Unity.TestIgnores)); - UnityPrint(UnityStrResultsIgnored); - UNITY_PRINT_EOL(); - if (Unity.TestFailures == 0U) - { - UnityPrintOk(); - } - else - { - UnityPrintFail(); -#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL - UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); -#endif - } - UNITY_PRINT_EOL(); - UNITY_FLUSH_CALL(); - UNITY_OUTPUT_COMPLETE(); - return (int)(Unity.TestFailures); -} - -/*----------------------------------------------- - * Command Line Argument Support - *-----------------------------------------------*/ -#ifdef UNITY_USE_COMMAND_LINE_ARGS - -char* UnityOptionIncludeNamed = NULL; -char* UnityOptionExcludeNamed = NULL; -int UnityVerbosity = 1; - -int UnityParseOptions(int argc, char** argv) -{ - UnityOptionIncludeNamed = NULL; - UnityOptionExcludeNamed = NULL; - - for (int i = 1; i < argc; i++) - { - if (argv[i][0] == '-') - { - switch(argv[i][1]) - { - case 'l': /* list tests */ - return -1; - case 'n': /* include tests with name including this string */ - case 'f': /* an alias for -n */ - if (argv[i][2] == '=') - UnityOptionIncludeNamed = &argv[i][3]; - else if (++i < argc) - UnityOptionIncludeNamed = argv[i]; - else - { - UnityPrint("ERROR: No Test String to Include Matches For"); - UNITY_PRINT_EOL(); - return 1; - } - break; - case 'q': /* quiet */ - UnityVerbosity = 0; - break; - case 'v': /* verbose */ - UnityVerbosity = 2; - break; - case 'x': /* exclude tests with name including this string */ - if (argv[i][2] == '=') - UnityOptionExcludeNamed = &argv[i][3]; - else if (++i < argc) - UnityOptionExcludeNamed = argv[i]; - else - { - UnityPrint("ERROR: No Test String to Exclude Matches For"); - UNITY_PRINT_EOL(); - return 1; - } - break; - default: - UnityPrint("ERROR: Unknown Option "); - UNITY_OUTPUT_CHAR(argv[i][1]); - UNITY_PRINT_EOL(); - return 1; - } - } - } - - return 0; -} - -int IsStringInBiggerString(const char* longstring, const char* shortstring) -{ - char* lptr = (char*)longstring; - char* sptr = (char*)shortstring; - char* lnext = lptr; - - if (*sptr == '*') - return 1; - - while (*lptr) - { - lnext = lptr + 1; - - /* If they current bytes match, go on to the next bytes */ - while (*lptr && *sptr && (*lptr == *sptr)) - { - lptr++; - sptr++; - - /* We're done if we match the entire string or up to a wildcard */ - if (*sptr == '*') - return 1; - if (*sptr == ',') - return 1; - if (*sptr == '"') - return 1; - if (*sptr == '\'') - return 1; - if (*sptr == ':') - return 2; - if (*sptr == 0) - return 1; - } - - /* Otherwise we start in the long pointer 1 character further and try again */ - lptr = lnext; - sptr = (char*)shortstring; - } - return 0; -} - -int UnityStringArgumentMatches(const char* str) -{ - int retval; - const char* ptr1; - const char* ptr2; - const char* ptrf; - - /* Go through the options and get the substrings for matching one at a time */ - ptr1 = str; - while (ptr1[0] != 0) - { - if ((ptr1[0] == '"') || (ptr1[0] == '\'')) - ptr1++; - - /* look for the start of the next partial */ - ptr2 = ptr1; - ptrf = 0; - do { - ptr2++; - if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) - ptrf = &ptr2[1]; - } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); - while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) - ptr2++; - - /* done if complete filename match */ - retval = IsStringInBiggerString(Unity.TestFile, ptr1); - if (retval == 1) - return retval; - - /* done if testname match after filename partial match */ - if ((retval == 2) && (ptrf != 0)) - { - if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) - return 1; - } - - /* done if complete testname match */ - if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) - return 1; - - ptr1 = ptr2; - } - - /* we couldn't find a match for any substrings */ - return 0; -} - -int UnityTestMatches(void) -{ - /* Check if this test name matches the included test pattern */ - int retval; - if (UnityOptionIncludeNamed) - { - retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); - } - else - retval = 1; - - /* Check if this test name matches the excluded test pattern */ - if (UnityOptionExcludeNamed) - { - if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) - retval = 0; - } - return retval; -} - -#endif /* UNITY_USE_COMMAND_LINE_ARGS */ -/*-----------------------------------------------*/ diff --git a/test/unity/unity.h b/test/unity/unity.h deleted file mode 100644 index 031ccc92..00000000 --- a/test/unity/unity.h +++ /dev/null @@ -1,293 +0,0 @@ -/* ========================================== - Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef UNITY_FRAMEWORK_H -#define UNITY_FRAMEWORK_H -#define UNITY - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "unity_internals.h" - -void setUp(void); -void tearDown(void); - -/*------------------------------------------------------- - * Configuration Options - *------------------------------------------------------- - * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. - - * Integers/longs/pointers - * - Unity attempts to automatically discover your integer sizes - * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in - * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in - * - If you cannot use the automatic methods above, you can force Unity by using these options: - * - define UNITY_SUPPORT_64 - * - set UNITY_INT_WIDTH - * - set UNITY_LONG_WIDTH - * - set UNITY_POINTER_WIDTH - - * Floats - * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons - * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT - * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats - * - define UNITY_FLOAT_VERBOSE to print floating point values in errors (uses sprintf) - * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons - * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) - * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE - * - define UNITY_DOUBLE_TYPE to specify something other than double - * - define UNITY_DOUBLE_VERBOSE to print floating point values in errors (uses sprintf) - * - define UNITY_VERBOSE_NUMBER_MAX_LENGTH to change maximum length of printed numbers (used by sprintf) - - * Output - * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired - * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure - - * Optimization - * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge - * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. - - * Test Cases - * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script - - * Parameterized Tests - * - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing - - * Tests with Arguments - * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity - - *------------------------------------------------------- - * Basic Fail and Ignore - *-------------------------------------------------------*/ - -#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) -#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) -#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) -#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) -#define TEST_ONLY() - -/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. - * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ -#define TEST_PASS() longjmp(Unity.AbortFrame, 1) - -/*------------------------------------------------------- - * Test Asserts (simple) - *-------------------------------------------------------*/ - -/* Boolean */ -#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") -#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") -#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") -#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") -#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") -#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") - -/* Integers (of all sizes) */ -#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") -#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, NULL) - -/* Integer Ranges (of all sizes) */ -#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) - -/* Structs and Strings */ -#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) - -/* Arrays */ -#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) - -/* Floating Point (If Enabled) */ -#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) - -/* Double (If Enabled) */ -#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) - -/*------------------------------------------------------- - * Test Asserts (with additional messages) - *-------------------------------------------------------*/ - -/* Boolean */ -#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) -#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) -#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) -#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) -#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) -#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) - -/* Integers (of all sizes) */ -#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, (message)) -#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, (message)) -#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, (message)) - -/* Integer Ranges (of all sizes) */ -#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) - -/* Structs and Strings */ -#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) - -/* Arrays */ -#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message)) - -/* Floating Point (If Enabled) */ -#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) - -/* Double (If Enabled) */ -#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) - -/* end of UNITY_FRAMEWORK_H */ -#ifdef __cplusplus -} -#endif -#endif diff --git a/test/unity/unity_internals.h b/test/unity/unity_internals.h deleted file mode 100644 index 8ccd66d5..00000000 --- a/test/unity/unity_internals.h +++ /dev/null @@ -1,749 +0,0 @@ -/* ========================================== - Unity Project - A Test Framework for C - Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef UNITY_INTERNALS_H -#define UNITY_INTERNALS_H - -#ifdef UNITY_INCLUDE_CONFIG_H -#include "unity_config.h" -#endif - -#include - -#ifndef UNITY_EXCLUDE_MATH_H -#include -#endif - -/* Unity Attempts to Auto-Detect Integer Types - * Attempt 1: UINT_MAX, ULONG_MAX in , or default to 32 bits - * Attempt 2: UINTPTR_MAX in , or default to same size as long - * The user may override any of these derived constants: - * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */ -#ifndef UNITY_EXCLUDE_STDINT_H -#include -#endif - -#ifndef UNITY_EXCLUDE_LIMITS_H -#include -#endif - -/*------------------------------------------------------- - * Guess Widths If Not Specified - *-------------------------------------------------------*/ - -/* Determine the size of an int, if not already specified. - * We cannot use sizeof(int), because it is not yet defined - * at this stage in the translation of the C program. - * Therefore, infer it from UINT_MAX if possible. */ -#ifndef UNITY_INT_WIDTH - #ifdef UINT_MAX - #if (UINT_MAX == 0xFFFF) - #define UNITY_INT_WIDTH (16) - #elif (UINT_MAX == 0xFFFFFFFF) - #define UNITY_INT_WIDTH (32) - #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) - #define UNITY_INT_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_INT_WIDTH (32) - #endif /* UINT_MAX */ -#endif - -/* Determine the size of a long, if not already specified. */ -#ifndef UNITY_LONG_WIDTH - #ifdef ULONG_MAX - #if (ULONG_MAX == 0xFFFF) - #define UNITY_LONG_WIDTH (16) - #elif (ULONG_MAX == 0xFFFFFFFF) - #define UNITY_LONG_WIDTH (32) - #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) - #define UNITY_LONG_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_LONG_WIDTH (32) - #endif /* ULONG_MAX */ -#endif - -/* Determine the size of a pointer, if not already specified. */ -#ifndef UNITY_POINTER_WIDTH - #ifdef UINTPTR_MAX - #if (UINTPTR_MAX <= 0xFFFF) - #define UNITY_POINTER_WIDTH (16) - #elif (UINTPTR_MAX <= 0xFFFFFFFF) - #define UNITY_POINTER_WIDTH (32) - #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) - #define UNITY_POINTER_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH - #endif /* UINTPTR_MAX */ -#endif - -/*------------------------------------------------------- - * Int Support (Define types based on detected sizes) - *-------------------------------------------------------*/ - -#if (UNITY_INT_WIDTH == 32) - typedef unsigned char _UU8; - typedef unsigned short _UU16; - typedef unsigned int _UU32; - typedef signed char _US8; - typedef signed short _US16; - typedef signed int _US32; -#elif (UNITY_INT_WIDTH == 16) - typedef unsigned char _UU8; - typedef unsigned int _UU16; - typedef unsigned long _UU32; - typedef signed char _US8; - typedef signed int _US16; - typedef signed long _US32; -#else - #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) -#endif - -/*------------------------------------------------------- - * 64-bit Support - *-------------------------------------------------------*/ - -#ifndef UNITY_SUPPORT_64 - #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 - #define UNITY_SUPPORT_64 - #endif -#endif - -#ifndef UNITY_SUPPORT_64 - /* No 64-bit Support */ - typedef _UU32 _U_UINT; - typedef _US32 _U_SINT; -#else - - /* 64-bit Support */ - #if (UNITY_LONG_WIDTH == 32) - typedef unsigned long long _UU64; - typedef signed long long _US64; - #elif (UNITY_LONG_WIDTH == 64) - typedef unsigned long _UU64; - typedef signed long _US64; - #else - #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) - #endif - typedef _UU64 _U_UINT; - typedef _US64 _U_SINT; - -#endif - -/*------------------------------------------------------- - * Pointer Support - *-------------------------------------------------------*/ - -#if (UNITY_POINTER_WIDTH == 32) - typedef _UU32 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 -#elif (UNITY_POINTER_WIDTH == 64) - typedef _UU64 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 -#elif (UNITY_POINTER_WIDTH == 16) - typedef _UU16 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 -#else - #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) -#endif - -#ifndef UNITY_PTR_ATTRIBUTE -#define UNITY_PTR_ATTRIBUTE -#endif - -#ifndef UNITY_INTERNAL_PTR -#define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* -/* #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const _UU8* */ -#endif - -/*------------------------------------------------------- - * Float Support - *-------------------------------------------------------*/ - -#ifdef UNITY_EXCLUDE_FLOAT - -/* No Floating Point Support */ -#undef UNITY_INCLUDE_FLOAT -#undef UNITY_FLOAT_PRECISION -#undef UNITY_FLOAT_TYPE -#undef UNITY_FLOAT_VERBOSE - -#else - -#ifndef UNITY_INCLUDE_FLOAT -#define UNITY_INCLUDE_FLOAT -#endif - -/* Floating Point Support */ -#ifndef UNITY_FLOAT_PRECISION -#define UNITY_FLOAT_PRECISION (0.00001f) -#endif -#ifndef UNITY_FLOAT_TYPE -#define UNITY_FLOAT_TYPE float -#endif -typedef UNITY_FLOAT_TYPE _UF; - -#ifndef isinf -/* The value of Inf - Inf is NaN */ -#define isinf(n) (isnan((n) - (n)) && !isnan(n)) -#endif - -#ifndef isnan -/* NaN is the only floating point value that does NOT equal itself. - * Therefore if n != n, then it is NaN. */ -#define isnan(n) ((n != n) ? 1 : 0) -#endif - -#ifndef isneg -#define isneg(n) ((n < 0.0f) ? 1 : 0) -#endif - -#ifndef ispos -#define ispos(n) ((n > 0.0f) ? 1 : 0) -#endif - -#endif - -/*------------------------------------------------------- - * Double Float Support - *-------------------------------------------------------*/ - -/* unlike FLOAT, we DON'T include by default */ -#ifndef UNITY_EXCLUDE_DOUBLE - #ifndef UNITY_INCLUDE_DOUBLE - #define UNITY_EXCLUDE_DOUBLE - #endif -#endif - -#ifdef UNITY_EXCLUDE_DOUBLE - - /* No Floating Point Support */ - #undef UNITY_DOUBLE_PRECISION - #undef UNITY_DOUBLE_TYPE - #undef UNITY_DOUBLE_VERBOSE - - #ifdef UNITY_INCLUDE_DOUBLE - #undef UNITY_INCLUDE_DOUBLE - #endif - - #ifdef UNITY_FLOAT_VERBOSE - typedef _UF _UD; - /* For parameter in UnityPrintFloat, double promotion required */ - #endif - -#else - - /* Double Floating Point Support */ - #ifndef UNITY_DOUBLE_PRECISION - #define UNITY_DOUBLE_PRECISION (1e-12f) - #endif - - #ifndef UNITY_DOUBLE_TYPE - #define UNITY_DOUBLE_TYPE double - #endif - typedef UNITY_DOUBLE_TYPE _UD; - -#endif - -#ifdef UNITY_DOUBLE_VERBOSE -#ifndef UNITY_FLOAT_VERBOSE -#define UNITY_FLOAT_VERBOSE -#endif -#endif - -/*------------------------------------------------------- - * Output Method: stdout (DEFAULT) - *-------------------------------------------------------*/ -#ifndef UNITY_OUTPUT_CHAR -/* Default to using putchar, which is defined in stdio.h */ -#include -#define UNITY_OUTPUT_CHAR(a) (void)putchar(a) -#else - /* If defined as something else, make sure we declare it here so it's ready for use */ - #ifndef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION -extern void UNITY_OUTPUT_CHAR(int); - #endif -#endif - -#ifndef UNITY_OUTPUT_FLUSH -/* Default to using fflush, which is defined in stdio.h */ -#include -#define UNITY_OUTPUT_FLUSH (void)fflush(stdout) -#else - /* If defined as something else, make sure we declare it here so it's ready for use */ - #ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION -extern void UNITY_OUTPUT_FLUSH(void); - #endif -#endif - -#ifndef UNITY_OUTPUT_FLUSH -#define UNITY_FLUSH_CALL() -#else -#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH -#endif - -#ifndef UNITY_PRINT_EOL -#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') -#endif - -#ifndef UNITY_OUTPUT_START -#define UNITY_OUTPUT_START() -#endif - -#ifndef UNITY_OUTPUT_COMPLETE -#define UNITY_OUTPUT_COMPLETE() -#endif - -/*------------------------------------------------------- - * Footprint - *-------------------------------------------------------*/ - -#ifndef UNITY_LINE_TYPE -#define UNITY_LINE_TYPE _U_UINT -#endif - -#ifndef UNITY_COUNTER_TYPE -#define UNITY_COUNTER_TYPE _U_UINT -#endif - -/*------------------------------------------------------- - * Language Features Available - *-------------------------------------------------------*/ -#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) -# ifdef __GNUC__ /* includes clang */ -# if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__) -# define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) -# endif -# endif -#endif - -#ifdef UNITY_NO_WEAK -# undef UNITY_WEAK_ATTRIBUTE -# undef UNITY_WEAK_PRAGMA -#endif - - -/*------------------------------------------------------- - * Internal Structs Needed - *-------------------------------------------------------*/ - -typedef void (*UnityTestFunction)(void); - -#define UNITY_DISPLAY_RANGE_INT (0x10) -#define UNITY_DISPLAY_RANGE_UINT (0x20) -#define UNITY_DISPLAY_RANGE_HEX (0x40) -#define UNITY_DISPLAY_RANGE_AUTO (0x80) - -typedef enum -{ -UNITY_DISPLAY_STYLE_INT = sizeof(int)+ UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, - UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, - UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, - UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, -#endif - -UNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, - UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, - UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, - UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, -#endif - - UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, - UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, - UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, -#endif - - UNITY_DISPLAY_STYLE_UNKNOWN -} UNITY_DISPLAY_STYLE_T; - -#ifndef UNITY_EXCLUDE_FLOAT -typedef enum _UNITY_FLOAT_TRAIT_T -{ - UNITY_FLOAT_IS_NOT_INF = 0, - UNITY_FLOAT_IS_INF, - UNITY_FLOAT_IS_NOT_NEG_INF, - UNITY_FLOAT_IS_NEG_INF, - UNITY_FLOAT_IS_NOT_NAN, - UNITY_FLOAT_IS_NAN, - UNITY_FLOAT_IS_NOT_DET, - UNITY_FLOAT_IS_DET, - UNITY_FLOAT_INVALID_TRAIT -} UNITY_FLOAT_TRAIT_T; -#endif - -struct _Unity -{ - const char* TestFile; - const char* CurrentTestName; -#ifndef UNITY_EXCLUDE_DETAILS - const char* CurrentDetail1; - const char* CurrentDetail2; -#endif - UNITY_LINE_TYPE CurrentTestLineNumber; - UNITY_COUNTER_TYPE NumberOfTests; - UNITY_COUNTER_TYPE TestFailures; - UNITY_COUNTER_TYPE TestIgnores; - UNITY_COUNTER_TYPE CurrentTestFailed; - UNITY_COUNTER_TYPE CurrentTestIgnored; - jmp_buf AbortFrame; -}; - -extern struct _Unity Unity; - -/*------------------------------------------------------- - * Test Suite Management - *-------------------------------------------------------*/ - -void UnityBegin(const char* filename); -int UnityEnd(void); -void UnityConcludeTest(void); -void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); - -/*------------------------------------------------------- - * Details Support - *-------------------------------------------------------*/ - -#ifdef UNITY_EXCLUDE_DETAILS -#define UNITY_CLR_DETAILS() -#define UNITY_SET_DETAIL(d1) -#define UNITY_SET_DETAILS(d1,d2) -#else -#define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = d2; } - -#ifndef UNITY_DETAIL1_NAME -#define UNITY_DETAIL1_NAME "Function" -#endif - -#ifndef UNITY_DETAIL2_NAME -#define UNITY_DETAIL2_NAME "Argument" -#endif -#endif - -/*------------------------------------------------------- - * Test Output - *-------------------------------------------------------*/ - -void UnityPrint(const char* string); -void UnityPrintMask(const _U_UINT mask, const _U_UINT number); -void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style); -void UnityPrintNumber(const _U_SINT number); -void UnityPrintNumberUnsigned(const _U_UINT number); -void UnityPrintNumberHex(const _U_UINT number, const char nibbles); - -#ifdef UNITY_FLOAT_VERBOSE -void UnityPrintFloat(const _UD number); -#endif - -/*------------------------------------------------------- - * Test Assertion Functions - *------------------------------------------------------- - * Use the macros below this section instead of calling - * these directly. The macros have a consistent naming - * convention and will pull in file and line information - * for you. */ - -void UnityAssertEqualNumber(const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertBits(const _U_SINT mask, - const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualString(const char* expected, - const char* actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualStringLen(const char* expected, - const char* actual, - const _UU32 length, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualStringArray( const char** expected, - const char** actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const _UU32 length, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertNumbersWithin(const _U_UINT delta, - const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityFail(const char* message, const UNITY_LINE_TYPE line); - -void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); - -#ifndef UNITY_EXCLUDE_FLOAT -void UnityAssertFloatsWithin(const _UF delta, - const _UF expected, - const _UF actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, - UNITY_PTR_ATTRIBUTE const _UF* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertFloatSpecial(const _UF actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style); -#endif - -#ifndef UNITY_EXCLUDE_DOUBLE -void UnityAssertDoublesWithin(const _UD delta, - const _UD expected, - const _UD actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, - UNITY_PTR_ATTRIBUTE const _UD* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertDoubleSpecial(const _UD actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style); -#endif - -/*------------------------------------------------------- - * Error Strings We Might Need - *-------------------------------------------------------*/ - -extern const char UnityStrErrFloat[]; -extern const char UnityStrErrDouble[]; -extern const char UnityStrErr64[]; - -/*------------------------------------------------------- - * Test Running Macros - *-------------------------------------------------------*/ - -#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) - -#define TEST_ABORT() {longjmp(Unity.AbortFrame, 1);} - -/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ -#ifndef RUN_TEST -#ifdef __STDC_VERSION__ -#if __STDC_VERSION__ >= 199901L -#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__)) -#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway) -#define RUN_TEST_FIRST_HELPER(first, ...) (first), #first -#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway) -#define RUN_TEST_SECOND_HELPER(first, second, ...) (second) -#endif -#endif -#endif - -/* If we can't do the tricky version, we'll just have to require them to always include the line number */ -#ifndef RUN_TEST -#ifdef CMOCK -#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) -#else -#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) -#endif -#endif - -#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) -#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) -#define UNITY_NEW_TEST(a) \ - Unity.CurrentTestName = (a); \ - Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ - Unity.NumberOfTests++; - -#ifndef UNITY_BEGIN -#define UNITY_BEGIN() UnityBegin(__FILE__) -#endif - -#ifndef UNITY_END -#define UNITY_END() UnityEnd() -#endif - -#define UNITY_UNUSED(x) (void)(sizeof(x)) - -/*----------------------------------------------- - * Command Line Argument Support - *-----------------------------------------------*/ - -#ifdef UNITY_USE_COMMAND_LINE_ARGS -int UnityParseOptions(int argc, char** argv); -int UnityTestMatches(void); -#endif - -/*------------------------------------------------------- - * Basic Fail and Ignore - *-------------------------------------------------------*/ - -#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) - -/*------------------------------------------------------- - * Test Asserts - *-------------------------------------------------------*/ - -#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));} -#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) -#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) - -#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU8 )(expected), (_U_SINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU16)(expected), (_U_SINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU32)(expected), (_U_SINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((_U_SINT)(mask), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line)) - -#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) - -#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UP)(expected), (_U_SINT)(_UP)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) -#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message) UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (_UU32)(len), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), 1, (message), (UNITY_LINE_TYPE)(line)) - -#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(_UP*)(expected), (UNITY_INTERNAL_PTR)(_UP*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) -#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((const char**)(expected), (const char**)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) - -#ifdef UNITY_SUPPORT_64 -#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#else -#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#endif - -#ifdef UNITY_EXCLUDE_FLOAT -#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#else -#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((_UF)(delta), (_UF)(expected), (_UF)(actual), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((_UF)(expected) * (_UF)UNITY_FLOAT_PRECISION, (_UF)(expected), (_UF)(actual), (UNITY_LINE_TYPE)(line), (message)) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray((_UF*)(expected), (_UF*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) -#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) -#endif - -#ifdef UNITY_EXCLUDE_DOUBLE -#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#else -#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((_UD)(delta), (_UD)(expected), (_UD)(actual), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((_UD)(expected) * (_UD)UNITY_DOUBLE_PRECISION, (_UD)expected, (_UD)actual, (UNITY_LINE_TYPE)(line), message) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((_UD*)(expected), (_UD*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) -#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) -#endif - -/* End of UNITY_INTERNALS_H */ -#endif