Compare commits

..
47 Commits
Author SHA1 Message Date
SChernykh 9a5be0a321 p2pool v2.1 2022-05-31 18:20:21 +02:00
SChernykh c203f6eb0a Fixed a new cppcheck issue 2022-05-31 16:51:09 +02:00
SChernykh b713f4e702 CI: added Linux aarch64 build 2022-05-31 16:38:28 +02:00
SChernykh 111087d96a Fixed block reward share calculation 2022-05-28 22:27:46 +02:00
SChernykh 9e7666d12f Fixed data races 2022-05-28 21:46:50 +02:00
SChernykh cb147773b5 Updated cppcheck workflow on Linux 2022-05-26 21:19:01 +02:00
SChernykh d84bef8f14 Added block reward share percent to miner api 2022-05-26 11:08:16 +02:00
SChernykh 32bb318af4 Fixed cppcheck workflow on Windows 2022-05-25 20:05:17 +02:00
SChernykh 055b5e2256 Updated dependencies 2022-05-25 12:54:40 +02:00
SChernykh c1754d122f Update RandomX 2022-05-24 15:42:37 +02:00
SChernykh 6d121122f8 Fixed compiler warnings in tests 2022-05-24 15:18:09 +02:00
SChernykh bfa8334aeb Fixed executable stack 2022-05-23 21:41:17 +02:00
SChernykh 0e222afd6a Exit if server startup fails 2022-05-23 15:50:25 +02:00
SChernykh b191962d32 Handle startup errors without calling abort() 2022-05-23 09:37:11 +02:00
SChernykh 1cf13e142a SideChain: fixed alternative chain detection 2022-05-16 15:59:48 +02:00
SChernykh 8f1f81749d StratumServer: reset cumulative hashes too 2022-05-16 14:36:11 +02:00
SChernykh 72d70eba16 SideChain: added "synchronized" log message 2022-05-16 01:48:37 +02:00
SChernykh ae3612f595 Fixed worker diff display when autodiff is off 2022-05-15 18:13:36 +02:00
SChernykh 37b6457054 Show worker hashrate only when autodiff is on 2022-05-15 01:15:21 +02:00
SChernykh 9579be5c7d Optimized SideChain::miner_count() 2022-05-12 22:18:08 +02:00
SChernykh d05d47fa75 Fixed compilation 2022-05-12 16:10:55 +02:00
SChernykh bd88c04e9e SideChain: mutex locks refactoring 2022-05-12 15:24:02 +02:00
SChernykh eb3a3872eb Fixed missing blocks download logic 2022-05-12 08:49:34 +02:00
SChernykh 5cea7be405 Allow only one pending get_miner_data 2022-05-12 01:09:59 +02:00
SChernykh 516c382fe4 Update keccak.cpp 2022-05-11 16:13:00 +02:00
SChernykh 710e55422a Ignore duplicate get_miner_data 2022-05-11 16:10:10 +02:00
SChernykh 3406cf78b4 Don't return stale chain tip to other peers 2022-05-11 15:07:54 +02:00
SChernykh 8fa354796c Reload peer list when there are no connections 2022-05-11 14:09:28 +02:00
SChernykh 6c6ef1c1b8 Restart ZMQ connection if it looks dead 2022-05-11 13:50:47 +02:00
SChernykh c3c326c680 Suppress MSVC warnings 2022-05-11 10:55:36 +02:00
SChernykh 92e20485b2 Log: don't allow side effects in LOG() calls 2022-05-10 21:41:53 +02:00
SChernykh edd782ac23 Fixed custom worker names 2022-05-10 14:01:10 +02:00
SChernykh a4d84e318d TCPServer: refactored Client constructor 2022-05-09 19:13:34 +02:00
SChernykh 08ee599f79 Use the same compilation flags for tests 2022-05-09 17:57:31 +02:00
SChernykh 134f2d68a3 Fixed data races 2022-05-09 16:10:55 +02:00
SChernykh d23c46ff84 Added bsr() function to util 2022-05-09 13:02:06 +02:00
SChernykh 820c5db5e8 Log: check for logrotate only once per loop 2022-05-09 09:58:43 +02:00
SChernykh 990916ab62 StratumServer: added autodiff
Autodiff is enabled by default, target time is 30 seconds. It can be disabled with `--no-autodiff` command line option.
2022-05-08 19:03:00 +02:00
SChernykh d4e362cd76 TCPServer: optimized Client struct size 2022-05-07 12:35:31 +02:00
SChernykh 1dd06cc509 Removed std::string to avoid memory allocation 2022-05-07 11:00:29 +02:00
SChernykh 2e2bd1d137 Added log padding 2022-05-06 20:04:01 +02:00
SChernykh 0818d91f4f StratumServer: added console command workers 2022-05-06 13:19:56 +02:00
SChernykh 6e1f34b168 Termux build instructions 2022-05-05 15:53:04 +02:00
SChernykh 1a35177633 Fixed unsafe usage of log::Stream buffers 2022-05-05 14:38:56 +02:00
SChernykh c45689b02b Fixed pthread_cancel detection 2022-05-03 21:03:06 +02:00
SChernykh 8f27d940e3 Don't ban localhost 2022-05-03 13:11:55 +02:00
SChernykh 6b4640c413 Fixes for Termux 2022-05-03 07:32:47 +02:00
57 changed files with 1086 additions and 432 deletions
+44
View File
@@ -53,6 +53,50 @@ jobs:
name: p2pool-${{ matrix.config.os }} name: p2pool-${{ matrix.config.os }}
path: build/p2pool path: build/p2pool
build-ubuntu-aarch64:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y git build-essential cmake gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu
- name: Checkout repository
uses: actions/checkout@v2
with:
submodules: true
- name: Build libuv
run: |
cd external/src/libuv
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++
make -j$(nproc)
- name: Build libzmq
run: |
cd external/src/libzmq
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF
make -j$(nproc)
- name: Build p2pool
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_STRIP=/usr/bin/aarch64-linux-gnu-strip -DSTATIC_LIBS=ON -DARCH_ID=aarch64
make -j$(nproc)
- name: Archive binary
uses: actions/upload-artifact@v2
with:
name: p2pool-ubuntu-latest-aarch64
path: build/p2pool
build-windows-msys2: build-windows-msys2:
runs-on: windows-latest runs-on: windows-latest
+22 -6
View File
@@ -12,14 +12,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install cppcheck
run: sudo apt update && sudo apt install cppcheck
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Checkout cppcheck
uses: actions/checkout@v3
with:
repository: danmar/cppcheck
path: cppcheck-main
- name: Build cppcheck
run: |
cd cppcheck-main
make -j$(nproc) cppcheck
- name: Run cppcheck - name: Run cppcheck
run: | run: |
cd cppcheck cd cppcheck
@@ -30,14 +38,22 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- name: Install cppcheck
run: choco install cppcheck
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Checkout cppcheck
uses: actions/checkout@v3
with:
repository: danmar/cppcheck
path: cppcheck-main
- name: Build cppcheck
run: |
cd cppcheck-main
& "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\msbuild.exe" /m /p:Configuration=Release /p:Platform=x64
- name: Setup cmake - name: Setup cmake
uses: lukka/get-cmake@latest uses: lukka/get-cmake@latest
+26 -3
View File
@@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 2.8.12)
project(p2pool) project(p2pool)
option(STATIC_BINARY "Build static binary" OFF) option(STATIC_BINARY "Build static binary" OFF)
option(STATIC_LIBS "Link libuv and libzmq statically" OFF)
option(WITH_RANDOMX "Include the RandomX library in the build. If this is turned off, p2pool will rely on monerod for verifying RandomX hashes" ON) option(WITH_RANDOMX "Include the RandomX library in the build. If this is turned off, p2pool will rely on monerod for verifying RandomX hashes" ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
if (${CMAKE_VERSION} VERSION_GREATER "3.5.2") if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0")
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT p2pool) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT p2pool)
endif() endif()
@@ -100,7 +101,7 @@ if (WIN32)
elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
set(LIBS ${LIBS} pthread) set(LIBS ${LIBS} pthread)
elseif (NOT APPLE) elseif (NOT APPLE)
set(LIBS ${LIBS} pthread gss dl) set(LIBS ${LIBS} pthread dl)
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC) if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
@@ -133,9 +134,31 @@ endif()
add_definitions(/DZMQ_STATIC) add_definitions(/DZMQ_STATIC)
include(CheckSymbolExists)
set(CMAKE_REQUIRED_FLAGS "${GENERAL_FLAGS}")
check_symbol_exists(pthread_cancel pthread.h HAVE_PTHREAD_CANCEL)
if (HAVE_PTHREAD_CANCEL)
add_definitions(/DHAVE_PTHREAD_CANCEL)
endif()
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("int main(){ return __builtin_clzll(1);}" HAVE_BUILTIN_CLZLL)
check_cxx_source_compiles("#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\nint main(){unsigned long r;_BitScanReverse64(&r,1);return r;}" HAVE_BITSCANREVERSE64)
if (HAVE_BUILTIN_CLZLL)
add_definitions(/DHAVE_BUILTIN_CLZLL)
endif()
if (HAVE_BITSCANREVERSE64)
add_definitions(/DHAVE_BITSCANREVERSE64)
endif()
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES}) add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES})
if (STATIC_BINARY) if (STATIC_BINARY OR STATIC_LIBS)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} ${CMAKE_PROJECT_NAME}) add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} ${CMAKE_PROJECT_NAME})
if (WITH_RANDOMX) if (WITH_RANDOMX)
+12
View File
@@ -271,6 +271,18 @@ cmake ..
make make
``` ```
### Android (Termux)
Run the following commands to install the necessary prerequisites, clone this repo, and build P2Pool locally in Termux:
```
pkg install git build-essential cmake libuv libzmq
git clone --recursive https://github.com/SChernykh/p2pool
cd p2pool
mkdir build && cd build
cmake ..
make -j$(nproc)
```
## Donations ## Donations
If you'd like to support further development of Monero P2Pool, you're welcome to send any amount of XMR to the following address: If you'd like to support further development of Monero P2Pool, you're welcome to send any amount of XMR to the following address:
+17 -14
View File
@@ -6,14 +6,15 @@ set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
if (CMAKE_CXX_COMPILER_ID MATCHES GNU) if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(GENERAL_FLAGS "-pthread")
set(WARNING_FLAGS "-Wall -Wextra -Werror") set(WARNING_FLAGS "-Wall -Wextra -Werror")
set(OPTIMIZATION_FLAGS "-Ofast -s") set(OPTIMIZATION_FLAGS "-Ofast -s")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
if (WIN32) if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
@@ -25,26 +26,28 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
endif() endif()
endif() endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC) elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
set(GENERAL_FLAGS "")
set(WARNING_FLAGS "/Wall /WX /sdl") set(WARNING_FLAGS "/Wall /WX /sdl")
set(SECURITY_FLAGS "/GS /guard:cf") set(SECURITY_FLAGS "/GS /guard:cf")
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL") set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
set(CMAKE_C_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address") set(CMAKE_C_FLAGS_DEBUG "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address") set(CMAKE_CXX_FLAGS_DEBUG "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_C_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT") set(CMAKE_C_FLAGS_RELEASE "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_CXX_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT") set(CMAKE_CXX_FLAGS_RELEASE "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang) elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(GENERAL_FLAGS "-pthread")
set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal -Werror") set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal -Werror")
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants") set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
endif() endif()
+2 -2
View File
@@ -1,9 +1,9 @@
../src/ ../src/
../external/src/ ../external/src/
../external/src/cryptonote/ ../external/src/cryptonote/
../external/src/libuv/ ../external/src/libuv/include/
../external/src/cppzmq/ ../external/src/cppzmq/
../external/src/libzmq/ ../external/src/libzmq/include/
../external/src/llhttp/ ../external/src/llhttp/
../external/src/RandomX/src/ ../external/src/RandomX/src/
../external/src/rapidjson/include ../external/src/rapidjson/include
+1 -1
View File
@@ -1,5 +1,5 @@
@echo off @echo off
"C:\Program Files\cppcheck\cppcheck.exe" --project=..\build\p2pool.vcxproj --project-configuration="Release|x64" -DZMQ_STATIC --platform=win64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt "..\cppcheck-main\bin\cppcheck.exe" --project=..\build\p2pool.vcxproj --project-configuration="Release|x64" -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN --platform=win64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt
findstr /V /C:"external\src" errors_full.txt > errors_filtered.txt findstr /V /C:"external\src" errors_full.txt > errors_filtered.txt
for /f %%i in ("errors_filtered.txt") do set size=%%~zi for /f %%i in ("errors_filtered.txt") do set size=%%~zi
if %size% gtr 0 ( if %size% gtr 0 (
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
cppcheck ../src -DZMQ_STATIC --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" -I ../src/ -I ../external/src/ -I ../external/src/cryptonote/ -I ../external/src/libuv/ -I ../external/src/cppzmq/ -I ../external/src/libzmq/ -I ../external/src/llhttp/ -I ../external/src/RandomX/src/ -I ../external/src/rapidjson/include -I ../external/src/robin-hood-hashing/src/include --suppressions-list=suppressions.txt --output-file=errors_full.txt ../cppcheck-main/cppcheck ../src -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt
grep -v 'external' errors_full.txt | grep -v 'unmatchedSuppression' > errors_filtered.txt grep -v 'external' errors_full.txt > errors_filtered.txt
if [ -s errors_filtered.txt ]; then if [ -s errors_filtered.txt ]; then
cat errors_filtered.txt cat errors_filtered.txt
exit 1 exit 1
-3
View File
@@ -1,6 +1,3 @@
missingIncludeSystem missingIncludeSystem
unusedFunction unusedFunction
useStlAlgorithm useStlAlgorithm
functionStatic
functionConst
unmatchedSuppression
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -2
View File
@@ -115,7 +115,7 @@ BlockTemplate& BlockTemplate::operator=(const BlockTemplate& b)
m_extraNonceOffsetInTemplate = b.m_extraNonceOffsetInTemplate; m_extraNonceOffsetInTemplate = b.m_extraNonceOffsetInTemplate;
m_numTransactionHashes = b.m_numTransactionHashes; m_numTransactionHashes = b.m_numTransactionHashes;
m_prevId = b.m_prevId; m_prevId = b.m_prevId;
m_height = b.m_height; m_height = b.m_height.load();
m_difficulty = b.m_difficulty; m_difficulty = b.m_difficulty;
m_seedHash = b.m_seedHash; m_seedHash = b.m_seedHash;
m_timestamp = b.m_timestamp; m_timestamp = b.m_timestamp;
@@ -575,7 +575,6 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
m_rewards.clear(); m_rewards.clear();
m_mempoolTxs.clear(); m_mempoolTxs.clear();
m_mempoolTxsOrder.clear(); m_mempoolTxsOrder.clear();
m_shares.clear();
} }
#if TEST_MEMPOOL_PICKING_ALGORITHM #if TEST_MEMPOOL_PICKING_ALGORITHM
+2 -3
View File
@@ -50,12 +50,11 @@ public:
void update_tx_keys(); void update_tx_keys();
FORCEINLINE uint64_t height() const { return m_height; } FORCEINLINE uint64_t height() const { return m_height; }
FORCEINLINE uint64_t timestamp() const { return m_timestamp; }
FORCEINLINE difficulty_type difficulty() const { return m_difficulty; } FORCEINLINE difficulty_type difficulty() const { return m_difficulty; }
void submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce); void submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce);
FORCEINLINE uint64_t final_reward() const { return m_finalReward; } FORCEINLINE const std::vector<MinerShare>& shares() const { return m_shares; }
private: private:
p2pool* m_pool; p2pool* m_pool;
@@ -83,7 +82,7 @@ private:
size_t m_numTransactionHashes; size_t m_numTransactionHashes;
hash m_prevId; hash m_prevId;
uint64_t m_height; std::atomic<uint64_t> m_height;
difficulty_type m_difficulty; difficulty_type m_difficulty;
hash m_seedHash; hash m_seedHash;
+17 -1
View File
@@ -19,22 +19,25 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable : 4005 4061 4365 4464 4625 4626 4668 4710 4711 4804 4820 5039 5045 5220) #pragma warning(disable : 4005 4061 4365 4464 4625 4626 4668 4710 4711 4804 4820 5039 5045 5220 5246)
#define FORCEINLINE __forceinline #define FORCEINLINE __forceinline
#define NOINLINE __declspec(noinline) #define NOINLINE __declspec(noinline)
#define LIKELY(expression) expression #define LIKELY(expression) expression
#define MSVC_PRAGMA(...) __pragma(__VA_ARGS__)
#elif __GNUC__ #elif __GNUC__
#define FORCEINLINE __attribute__((always_inline)) inline #define FORCEINLINE __attribute__((always_inline)) inline
#define NOINLINE __attribute__((noinline)) #define NOINLINE __attribute__((noinline))
#define LIKELY(expression) __builtin_expect(expression, 1) #define LIKELY(expression) __builtin_expect(expression, 1)
#define MSVC_PRAGMA(...)
#else #else
#define FORCEINLINE inline #define FORCEINLINE inline
#define NOINLINE #define NOINLINE
#define LIKELY(expression) expression #define LIKELY(expression) expression
#define MSVC_PRAGMA(...)
#endif #endif
@@ -198,11 +201,16 @@ struct difficulty_type
FORCEINLINE bool operator==(const difficulty_type& other) const { return (lo == other.lo) && (hi == other.hi); } FORCEINLINE bool operator==(const difficulty_type& other) const { return (lo == other.lo) && (hi == other.hi); }
FORCEINLINE bool operator!=(const difficulty_type& other) const { return (lo != other.lo) || (hi != other.hi); } FORCEINLINE bool operator!=(const difficulty_type& other) const { return (lo != other.lo) || (hi != other.hi); }
FORCEINLINE bool operator==(uint64_t other) const { return (lo == other) && (hi == 0); }
FORCEINLINE bool operator!=(uint64_t other) const { return (lo != other) || (hi != 0); }
friend std::ostream& operator<<(std::ostream& s, const difficulty_type& d); friend std::ostream& operator<<(std::ostream& s, const difficulty_type& d);
friend std::istream& operator>>(std::istream& s, difficulty_type& d); friend std::istream& operator>>(std::istream& s, difficulty_type& d);
FORCEINLINE double to_double() const { return static_cast<double>(hi) * 18446744073709551616.0 + static_cast<double>(lo); } FORCEINLINE double to_double() const { return static_cast<double>(hi) * 18446744073709551616.0 + static_cast<double>(lo); }
FORCEINLINE bool empty() const { return (lo == 0) && (hi == 0); }
// Finds a 64-bit target for mining (target = 2^64 / difficulty) and rounds up the result of division // Finds a 64-bit target for mining (target = 2^64 / difficulty) and rounds up the result of division
// Because of that, there's a very small chance that miners will find a hash that meets the target but is still wrong (hash * difficulty >= 2^256) // Because of that, there's a very small chance that miners will find a hash that meets the target but is still wrong (hash * difficulty >= 2^256)
// A proper difficulty check is in check_pow() // A proper difficulty check is in check_pow()
@@ -309,6 +317,14 @@ struct raw_ip
} }
FORCEINLINE bool operator!=(const raw_ip& other) const { return !operator==(other); } FORCEINLINE bool operator!=(const raw_ip& other) const { return !operator==(other); }
FORCEINLINE bool is_localhost() const
{
static constexpr raw_ip localhost_ipv4 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 };
static constexpr raw_ip localhost_ipv6 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
return (*this == localhost_ipv4) || (*this == localhost_ipv6);
}
}; };
static_assert(sizeof(raw_ip) == 16, "struct raw_ip has invalid size"); static_assert(sizeof(raw_ip) == 16, "struct raw_ip has invalid size");
+15 -2
View File
@@ -27,6 +27,10 @@
#include "side_chain.h" #include "side_chain.h"
#include <iostream> #include <iostream>
#ifdef HAVE_PTHREAD_CANCEL
#include <pthread.h>
#endif
static constexpr char log_category_prefix[] = "ConsoleCommands "; static constexpr char log_category_prefix[] = "ConsoleCommands ";
namespace p2pool { namespace p2pool {
@@ -45,7 +49,7 @@ ConsoleCommands::~ConsoleCommands()
#ifdef _WIN32 #ifdef _WIN32
TerminateThread(reinterpret_cast<HANDLE>(m_worker->native_handle()), 0); TerminateThread(reinterpret_cast<HANDLE>(m_worker->native_handle()), 0);
#else #elif defined HAVE_PTHREAD_CANCEL
pthread_cancel(m_worker->native_handle()); pthread_cancel(m_worker->native_handle());
#endif #endif
@@ -72,7 +76,7 @@ typedef struct cmd {
cmdfunc *func; cmdfunc *func;
} cmd; } cmd;
static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_showbans, do_outpeers, do_inpeers, do_exit; static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_showworkers, do_showbans, do_outpeers, do_inpeers, do_exit;
#ifdef WITH_RANDOMX #ifdef WITH_RANDOMX
static cmdfunc do_start_mining, do_stop_mining; static cmdfunc do_start_mining, do_stop_mining;
@@ -85,6 +89,7 @@ static cmd cmds[] = {
{ STRCONST("addpeers"), "<peeraddr>", "add peer", do_addpeers }, { STRCONST("addpeers"), "<peeraddr>", "add peer", do_addpeers },
{ STRCONST("droppeers"), "", "disconnect all peers", do_droppeers }, { STRCONST("droppeers"), "", "disconnect all peers", do_droppeers },
{ STRCONST("peers"), "", "show all peers", do_showpeers }, { STRCONST("peers"), "", "show all peers", do_showpeers },
{ STRCONST("workers"), "", "show all connected workers", do_showworkers },
{ STRCONST("bans"), "", "show all banned IPs", do_showbans }, { STRCONST("bans"), "", "show all banned IPs", do_showbans },
{ STRCONST("outpeers"), "", "set maximum number of outgoing connections", do_outpeers }, { STRCONST("outpeers"), "", "set maximum number of outgoing connections", do_outpeers },
{ STRCONST("inpeers"), "", "set maximum number of incoming connections", do_inpeers }, { STRCONST("inpeers"), "", "set maximum number of incoming connections", do_inpeers },
@@ -154,6 +159,14 @@ static int do_showpeers(p2pool* m_pool, const char* /* args */)
return 0; return 0;
} }
static int do_showworkers(p2pool* m_pool, const char* /* args */)
{
if (m_pool->stratum_server()) {
m_pool->stratum_server()->show_workers();
}
return 0;
}
static int do_showbans(p2pool* m_pool, const char* /* args */) static int do_showbans(p2pool* m_pool, const char* /* args */)
{ {
if (m_pool->stratum_server()) { if (m_pool->stratum_server()) {
+1
View File
@@ -238,6 +238,7 @@ private:
struct DerivationEntry struct DerivationEntry
{ {
hash derivation; hash derivation;
// cppcheck-suppress unusedStructMember
uint8_t view_tag; uint8_t view_tag;
}; };
+1 -1
View File
@@ -72,7 +72,7 @@ JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, C
m_request.reserve(std::max<size_t>(len + 128, log::Stream::BUF_SIZE + 1)); m_request.reserve(std::max<size_t>(len + 128, log::Stream::BUF_SIZE + 1));
m_request.resize(log::Stream::BUF_SIZE + 1); m_request.resize(log::Stream::BUF_SIZE + 1);
log::Stream s(m_request.data()); log::Stream s(m_request.data(), m_request.size());
s << "POST " << uri << " HTTP/1.1\nContent-Type: application/json\nContent-Length: " << len << "\n\n"; s << "POST " << uri << " HTTP/1.1\nContent-Type: application/json\nContent-Length: " << len << "\n\n";
m_request.resize(s.m_pos); m_request.resize(s.m_pos);
+1
View File
@@ -71,6 +71,7 @@ private:
static void on_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); static void on_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
void on_read(const char* data, size_t size); void on_read(const char* data, size_t size);
// cppcheck-suppress functionConst
void close(); void close();
static void on_close(uv_handle_t* handle); static void on_close(uv_handle_t* handle);
+24 -57
View File
@@ -48,7 +48,7 @@ NOINLINE void keccakf(uint64_t* st)
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
#define X(i) { \ #define THETA(i) { \
const uint64_t t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \ const uint64_t t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \
st[i + 0 ] ^= t; \ st[i + 0 ] ^= t; \
st[i + 5] ^= t; \ st[i + 5] ^= t; \
@@ -57,9 +57,11 @@ NOINLINE void keccakf(uint64_t* st)
st[i + 20] ^= t; \ st[i + 20] ^= t; \
} }
X(0); X(1); X(2); X(3); X(4); THETA(0);
THETA(1);
#undef X THETA(2);
THETA(3);
THETA(4);
// Rho Pi // Rho Pi
const uint64_t t = st[1]; const uint64_t t = st[1];
@@ -89,59 +91,24 @@ NOINLINE void keccakf(uint64_t* st)
st[10] = ROTL64(t, 1); st[10] = ROTL64(t, 1);
// Chi // Chi
// unrolled loop, where only last iteration is different #define CHI(j) { \
int j = 0; const uint64_t st0 = st[j ]; \
bc[0] = st[j + 0]; const uint64_t st1 = st[j + 1]; \
bc[1] = st[j + 1]; const uint64_t st2 = st[j + 2]; \
const uint64_t st3 = st[j + 3]; \
const uint64_t st4 = st[j + 4]; \
st[j ] ^= ~st1 & st2; \
st[j + 1] ^= ~st2 & st3; \
st[j + 2] ^= ~st3 & st4; \
st[j + 3] ^= ~st4 & st0; \
st[j + 4] ^= ~st0 & st1; \
}
st[j + 0] ^= (~st[j + 1]) & st[j + 2]; CHI( 0);
st[j + 1] ^= (~st[j + 2]) & st[j + 3]; CHI( 5);
st[j + 2] ^= (~st[j + 3]) & st[j + 4]; CHI(10);
st[j + 3] ^= (~st[j + 4]) & bc[0]; CHI(15);
st[j + 4] ^= (~bc[0]) & bc[1]; CHI(20);
j = 5;
bc[0] = st[j + 0];
bc[1] = st[j + 1];
st[j + 0] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 10;
bc[0] = st[j + 0];
bc[1] = st[j + 1];
st[j + 0] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 15;
bc[0] = st[j + 0];
bc[1] = st[j + 1];
st[j + 0] ^= (~st[j + 1]) & st[j + 2];
st[j + 1] ^= (~st[j + 2]) & st[j + 3];
st[j + 2] ^= (~st[j + 3]) & st[j + 4];
st[j + 3] ^= (~st[j + 4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
j = 20;
bc[0] = st[j + 0];
bc[1] = st[j + 1];
bc[2] = st[j + 2];
bc[3] = st[j + 3];
bc[4] = st[j + 4];
st[j + 0] ^= (~bc[1]) & bc[2];
st[j + 1] ^= (~bc[2]) & bc[3];
st[j + 2] ^= (~bc[3]) & bc[4];
st[j + 3] ^= (~bc[4]) & bc[0];
st[j + 4] ^= (~bc[0]) & bc[1];
// Iota // Iota
st[0] ^= keccakf_rndc[round]; st[0] ^= keccakf_rndc[round];
@@ -173,7 +140,7 @@ NOINLINE void keccak(const uint8_t* in, int inlen, uint8_t* md, int mdlen)
temp[rsiz - 1] |= 0x80; temp[rsiz - 1] |= 0x80;
for (int i = 0; i < rsizw; i++) { for (int i = 0; i < rsizw; i++) {
st[i] ^= ((uint64_t*)temp)[i]; st[i] ^= reinterpret_cast<uint64_t*>(temp)[i];
} }
keccakf(st); keccakf(st);
+7 -10
View File
@@ -194,15 +194,6 @@ private:
fwrite(p, 1, size, (severity == 1) ? stdout : stderr); fwrite(p, 1, size, (severity == 1) ? stdout : stderr);
#endif #endif
// Reopen the log file if it's been moved (logrotate support)
if (m_logFile.is_open()) {
struct stat buf;
if (stat(log_file_name, &buf) != 0) {
m_logFile.close();
m_logFile.open(log_file_name, std::ios::app | std::ios::binary);
}
}
if (m_logFile.is_open()) { if (m_logFile.is_open()) {
if (c) { if (c) {
strip_colors(p, size); strip_colors(p, size);
@@ -232,6 +223,13 @@ private:
// Flush the log file only after all pending log lines have been written // Flush the log file only after all pending log lines have been written
if (m_logFile.is_open()) { if (m_logFile.is_open()) {
m_logFile.flush(); m_logFile.flush();
// Reopen the log file if it's been moved (logrotate support)
struct stat buf;
if (stat(log_file_name, &buf) != 0) {
m_logFile.close();
m_logFile.open(log_file_name, std::ios::app | std::ios::binary);
}
} }
} while (!stopped); } while (!stopped);
} }
@@ -278,7 +276,6 @@ static Worker worker;
#endif // P2POOL_LOG_DISABLE #endif // P2POOL_LOG_DISABLE
// cppcheck-suppress uninitMemberVar
NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf) NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
{ {
m_buf[0] = static_cast<char>(severity); m_buf[0] = static_cast<char>(severity);
+109 -11
View File
@@ -35,8 +35,10 @@ struct Stream
{ {
enum params : int { BUF_SIZE = 1024 - 1 }; enum params : int { BUF_SIZE = 1024 - 1 };
explicit FORCEINLINE Stream(char* buf) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(BUF_SIZE) {} template<size_t N>
FORCEINLINE Stream(char* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(static_cast<int>(size) - 1) {} explicit FORCEINLINE Stream(char (&buf)[N]) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(N - 1) {}
FORCEINLINE Stream(void* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(reinterpret_cast<char*>(buf)), m_bufSize(static_cast<int>(size) - 1) {}
template<typename T> template<typename T>
struct Entry struct Entry
@@ -182,7 +184,10 @@ INT_ENTRY(unsigned long)
template<typename T, int base> template<typename T, int base>
struct BasedValue struct BasedValue
{ {
explicit FORCEINLINE BasedValue(T value) : m_value(value) {} explicit FORCEINLINE BasedValue(T value) : m_value(value)
{
static_assert(std::is_integral<T>::value, "Must be an integer type here");
}
T m_value; T m_value;
}; };
@@ -190,7 +195,7 @@ struct BasedValue
template<typename T, int base> template<typename T, int base>
struct Stream::Entry<BasedValue<T, base>> struct Stream::Entry<BasedValue<T, base>>
{ {
static FORCEINLINE void put(BasedValue<T, base>&& data, Stream* wrapper) static FORCEINLINE void put(BasedValue<T, base> data, Stream* wrapper)
{ {
wrapper->writeInt<T, base>(data.m_value); wrapper->writeInt<T, base>(data.m_value);
} }
@@ -302,6 +307,7 @@ struct Hashrate
{ {
FORCEINLINE Hashrate() : m_data(0), m_valid(false) {} FORCEINLINE Hashrate() : m_data(0), m_valid(false) {}
explicit FORCEINLINE Hashrate(uint64_t data) : m_data(data), m_valid(true) {} explicit FORCEINLINE Hashrate(uint64_t data) : m_data(data), m_valid(true) {}
FORCEINLINE Hashrate(uint64_t data, bool valid) : m_data(data), m_valid(valid) {}
uint64_t m_data; uint64_t m_data;
bool m_valid; bool m_valid;
@@ -309,7 +315,7 @@ struct Hashrate
template<> struct log::Stream::Entry<Hashrate> template<> struct log::Stream::Entry<Hashrate>
{ {
static NOINLINE void put(Hashrate&& value, Stream* wrapper) static NOINLINE void put(const Hashrate& value, Stream* wrapper)
{ {
if (!value.m_valid) { if (!value.m_valid) {
return; return;
@@ -354,7 +360,7 @@ struct XMRAmount
template<> struct log::Stream::Entry<XMRAmount> template<> struct log::Stream::Entry<XMRAmount>
{ {
static NOINLINE void put(XMRAmount&& value, Stream* wrapper) static NOINLINE void put(XMRAmount value, Stream* wrapper)
{ {
constexpr uint64_t denomination = 1000000000000ULL; constexpr uint64_t denomination = 1000000000000ULL;
@@ -372,8 +378,7 @@ template<> struct log::Stream::Entry<XMRAmount>
template<> struct log::Stream::Entry<NetworkType> template<> struct log::Stream::Entry<NetworkType>
{ {
// cppcheck-suppress constParameter static NOINLINE void put(NetworkType value, Stream* wrapper)
static NOINLINE void put(const NetworkType& value, Stream* wrapper)
{ {
switch (value) { switch (value) {
case NetworkType::Invalid: *wrapper << "invalid"; break; case NetworkType::Invalid: *wrapper << "invalid"; break;
@@ -384,6 +389,68 @@ template<> struct log::Stream::Entry<NetworkType>
} }
}; };
struct Duration
{
explicit FORCEINLINE Duration(uint64_t data) : m_data(data) {}
uint64_t m_data;
};
template<> struct log::Stream::Entry<Duration>
{
static NOINLINE void put(Duration value, Stream* wrapper)
{
const uint64_t uptime = value.m_data;
const int64_t s = uptime % 60;
const int64_t m = (uptime / 60) % 60;
const int64_t h = (uptime / 3600) % 24;
const int64_t d = uptime / 86400;
if (d > 0) {
*wrapper << d << "d ";
}
*wrapper << h << "h " << m << "m " << s << 's';
}
};
template<typename T>
struct PadRight
{
FORCEINLINE PadRight(const T& value, int len) : m_value(value), m_len(len) {}
const T& m_value;
int m_len;
// Declare it to make compiler happy
PadRight(const PadRight&);
private:
PadRight& operator=(const PadRight&) = delete;
PadRight& operator=(PadRight&&) = delete;
};
template<typename T> FORCEINLINE PadRight<T> pad_right(const T& value, int len) { return PadRight<T>(value, len); }
template<typename T>
struct log::Stream::Entry<PadRight<T>>
{
static NOINLINE void put(PadRight<T>&& data, Stream* wrapper)
{
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s(buf);
s << data.m_value;
const int len = std::min<int>(data.m_len, log::Stream::BUF_SIZE);
if (s.m_pos < len) {
memset(buf + s.m_pos, ' ', static_cast<size_t>(len) - s.m_pos);
s.m_pos = len;
}
wrapper->writeBuf(buf, s.m_pos);
}
};
void put_rawip(const raw_ip& value, Stream* wrapper); void put_rawip(const raw_ip& value, Stream* wrapper);
template<> struct log::Stream::Entry<raw_ip> template<> struct log::Stream::Entry<raw_ip>
@@ -402,16 +469,47 @@ namespace {
#define CONCAT(a, b) CONCAT2(a, b) #define CONCAT(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a##b #define CONCAT2(a, b) a##b
// This is to check that LOG() call doesn't modify variables in scope, making program behavior dependent on the log level:
//
// int some_func(int& n) { return ++n; }
// ...
// LOGINFO(1, "Some important value: " << some_func(n));
//
// will not compile because the dummy lambda capture uses const-qualified copies of all variables.
//
// The check is "free": compiler will remove it entirely in release builds.
struct DummyStream
{
template<typename T>
FORCEINLINE DummyStream& operator<<(const T&)
{
return *this;
}
};
#define SIDE_EFFECT_CHECK(level, ...) \
do { \
if (0) { \
MSVC_PRAGMA(warning(suppress:26444)) \
[=]() { \
log::DummyStream x; \
x << level << __VA_ARGS__; \
}; \
} \
} while (0)
#ifdef P2POOL_LOG_DISABLE #ifdef P2POOL_LOG_DISABLE
#define LOGINFO(level, ...) #define LOGINFO(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
#define LOGWARN(level, ...) #define LOGWARN(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
#define LOGERR(level, ...) #define LOGERR(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
#else #else
#define LOG(level, severity, ...) \ #define LOG(level, severity, ...) \
do { \ do { \
SIDE_EFFECT_CHECK(level, __VA_ARGS__); \
if (level <= log::GLOBAL_LOG_LEVEL) { \ if (level <= log::GLOBAL_LOG_LEVEL) { \
log::Writer CONCAT(log_wrapper_, __LINE__)(severity); \ log::Writer CONCAT(log_wrapper_, __LINE__)(severity); \
CONCAT(log_wrapper_, __LINE__) << log::Gray() << log_category_prefix; \ CONCAT(log_wrapper_, __LINE__) << log::Gray() << log_category_prefix; \
+8 -2
View File
@@ -44,7 +44,8 @@ void p2pool_usage()
"--out-peers N Maximum number of outgoing connections for p2p server (any value between 10 and 1000)\n" "--out-peers N Maximum number of outgoing connections for p2p server (any value between 10 and 1000)\n"
"--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 1000)\n" "--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 1000)\n"
"--start-mining N Start built-in miner using N threads (any value between 1 and 64)\n" "--start-mining N Start built-in miner using N threads (any value between 1 and 64)\n"
"--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from %d to %d.\n" "--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from %d to %d\n"
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum\n"
"--help Show this help message\n\n" "--help Show this help message\n\n"
"Example command line:\n\n" "Example command line:\n\n"
"%s --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:%d --p2p 0.0.0.0:%d\n\n", "%s --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:%d --p2p 0.0.0.0:%d\n\n",
@@ -84,10 +85,15 @@ int main(int argc, char* argv[])
memory_tracking_start(); memory_tracking_start();
p2pool::init_crypto_cache(); p2pool::init_crypto_cache();
{
try {
p2pool::p2pool pool(argc, argv); p2pool::p2pool pool(argc, argv);
result = pool.run(); result = pool.run();
} }
catch (...) {
result = 1;
}
p2pool::destroy_crypto_cache(); p2pool::destroy_crypto_cache();
memory_tracking_stop(); memory_tracking_stop();
+2
View File
@@ -236,7 +236,9 @@ NOINLINE void operator delete(void* p, size_t) noexcept { p2pool::free_hook(p);
NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::free_hook(p); } NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::free_hook(p); }
#else #else
// cppcheck-suppress functionStatic
void memory_tracking_start() {} void memory_tracking_start() {}
// cppcheck-suppress functionStatic
void memory_tracking_stop() {} void memory_tracking_stop() {}
namespace p2pool { namespace p2pool {
+5 -1
View File
@@ -24,6 +24,7 @@
#include "randomx.h" #include "randomx.h"
#include "params.h" #include "params.h"
#include "p2pool_api.h" #include "p2pool_api.h"
#include "side_chain.h"
#include <thread> #include <thread>
static constexpr char log_category_prefix[] = "Miner "; static constexpr char log_category_prefix[] = "Miner ";
@@ -101,8 +102,10 @@ void Miner::on_block(const BlockTemplate& block)
m_totalHashes += hash_count; m_totalHashes += hash_count;
if (m_pool->api() && m_pool->params().m_localStats) { if (m_pool->api() && m_pool->params().m_localStats) {
const double block_reward_share_percent = m_pool->side_chain().get_reward_share(m_pool->params().m_wallet) * 100.0;
m_pool->api()->set(p2pool_api::Category::LOCAL, "miner", m_pool->api()->set(p2pool_api::Category::LOCAL, "miner",
[cur_ts, hash_count, dt, this](log::Stream& s) [cur_ts, hash_count, dt, block_reward_share_percent, this](log::Stream& s)
{ {
const uint64_t hr = (dt > 0.0) ? static_cast<uint64_t>(hash_count / dt) : 0; const uint64_t hr = (dt > 0.0) ? static_cast<uint64_t>(hash_count / dt) : 0;
const double time_running = static_cast<double>(duration_cast<milliseconds>(cur_ts - m_startTimestamp).count()) / 1e3; const double time_running = static_cast<double>(duration_cast<milliseconds>(cur_ts - m_startTimestamp).count()) / 1e3;
@@ -111,6 +114,7 @@ void Miner::on_block(const BlockTemplate& block)
<< ",\"total_hashes\":" << m_totalHashes << ",\"total_hashes\":" << m_totalHashes
<< ",\"time_running\":" << time_running << ",\"time_running\":" << time_running
<< ",\"shares_found\":" << m_sharesFound.load() << ",\"shares_found\":" << m_sharesFound.load()
<< ",\"block_reward_share_percent\":" << block_reward_share_percent
<< ",\"threads\":" << m_threads << ",\"threads\":" << m_threads
<< "}"; << "}";
}); });
+103 -44
View File
@@ -37,6 +37,8 @@ static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
static constexpr int DEFAULT_BACKLOG = 16; static constexpr int DEFAULT_BACKLOG = 16;
static constexpr uint64_t DEFAULT_BAN_TIME = 600; static constexpr uint64_t DEFAULT_BAN_TIME = 600;
static constexpr size_t SEND_BUF_MIN_SIZE = 256;
#include "tcp_server.inl" #include "tcp_server.inl"
namespace p2pool { namespace p2pool {
@@ -75,7 +77,7 @@ P2PServer::P2PServer(p2pool* pool)
int err = uv_async_init(&m_loop, &m_broadcastAsync, on_broadcast); int err = uv_async_init(&m_loop, &m_broadcastAsync, on_broadcast);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
return; panic();
} }
m_broadcastAsync.data = this; m_broadcastAsync.data = this;
m_broadcastQueue.reserve(2); m_broadcastQueue.reserve(2);
@@ -149,6 +151,7 @@ void P2PServer::clear_cached_blocks()
WriteLock lock(m_cachedBlocksLock); WriteLock lock(m_cachedBlocksLock);
// cppcheck-suppress identicalConditionAfterEarlyExit
if (!m_cachedBlocks) { if (!m_cachedBlocks) {
return; return;
} }
@@ -288,6 +291,7 @@ void P2PServer::update_peer_connections()
if (!has_good_peers && ((m_timerCounter % 30) == 0)) { if (!has_good_peers && ((m_timerCounter % 30) == 0)) {
LOGERR(1, "no connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!!!"); LOGERR(1, "no connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!!!");
load_peer_list();
if (m_peerListMonero.empty()) { if (m_peerListMonero.empty()) {
load_monerod_peer_list(); load_monerod_peer_list();
} }
@@ -310,9 +314,14 @@ void P2PServer::update_peer_list()
client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61)); client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61));
const bool result = send(client, const bool result = send(client,
[](void* buf) [](void* buf, size_t buf_size)
{ {
LOGINFO(5, "sending PEER_LIST_REQUEST"); LOGINFO(5, "sending PEER_LIST_REQUEST");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
*reinterpret_cast<uint8_t*>(buf) = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST); *reinterpret_cast<uint8_t*>(buf) = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST);
return 1; return 1;
}); });
@@ -406,8 +415,13 @@ void P2PServer::save_peer_list()
void P2PServer::load_peer_list() void P2PServer::load_peer_list()
{ {
size_t old_size;
{
MutexLock lock(m_peerListLock);
old_size = m_peerList.size();
}
std::string saved_list; std::string saved_list;
const size_t old_size = m_peerList.size();
// Load peers from seed nodes if we're on the default or mini sidechain // Load peers from seed nodes if we're on the default or mini sidechain
auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) { auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) {
@@ -417,7 +431,7 @@ void P2PServer::load_peer_list()
addrinfo hints{}; addrinfo hints{};
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
addrinfo* result; addrinfo* result;
const int err = getaddrinfo(nodes[i], nullptr, &hints, &result); const int err = getaddrinfo(nodes[i], nullptr, &hints, &result);
@@ -426,7 +440,9 @@ void P2PServer::load_peer_list()
const char* addr_str; const char* addr_str;
char addr_str_buf[64]; char addr_str_buf[64];
char buf[log::Stream::BUF_SIZE + 1]; char buf[128];
buf[0] = '\0';
log::Stream s(buf); log::Stream s(buf);
if (r->ai_family == AF_INET6) { if (r->ai_family == AF_INET6) {
@@ -443,7 +459,7 @@ void P2PServer::load_peer_list()
} }
if (s.m_pos) { if (s.m_pos) {
LOGINFO(4, "added " << static_cast<char*>(buf) << " from " << nodes[i]); LOGINFO(4, "added " << static_cast<const char*>(buf) << " from " << nodes[i]);
if (!saved_list.empty()) { if (!saved_list.empty()) {
saved_list += ','; saved_list += ',';
} }
@@ -542,33 +558,35 @@ void P2PServer::load_monerod_peer_list()
JSONRPCRequest::call(params.m_host.c_str(), params.m_rpcPort, "/get_peer_list", JSONRPCRequest::call(params.m_host.c_str(), params.m_rpcPort, "/get_peer_list",
[this](const char* data, size_t size) [this](const char* data, size_t size)
{ {
constexpr char err_str[] = "/get_peer_list RPC request returned invalid JSON "; #define ERR_STR "/get_peer_list RPC request returned invalid JSON "
using namespace rapidjson; using namespace rapidjson;
Document doc; Document doc;
if (doc.Parse(data, size).HasParseError()) { if (doc.Parse(data, size).HasParseError()) {
LOGWARN(4, err_str << "(parse error)"); LOGWARN(4, ERR_STR "(parse error)");
return; return;
} }
if (!doc.IsObject()) { if (!doc.IsObject()) {
LOGWARN(4, err_str << "(not an object)"); LOGWARN(4, ERR_STR "(not an object)");
return; return;
} }
if (!doc.HasMember("white_list")) { if (!doc.HasMember("white_list")) {
LOGWARN(4, err_str << "('white_list' not found)"); LOGWARN(4, ERR_STR "('white_list' not found)");
return; return;
} }
const auto& white_list = doc["white_list"]; const auto& white_list = doc["white_list"];
if (!white_list.IsArray()) { if (!white_list.IsArray()) {
LOGWARN(4, err_str << "('white_list' is not an array)"); LOGWARN(4, ERR_STR "('white_list' is not an array)");
return; return;
} }
#undef ERR_STR
const int port = m_pool->side_chain().is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT; const int port = m_pool->side_chain().is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT;
const SizeType n = white_list.Size(); const SizeType n = white_list.Size();
@@ -780,7 +798,8 @@ void P2PServer::on_broadcast()
} }
for (Broadcast* data : broadcast_queue) { for (Broadcast* data : broadcast_queue) {
send(client, [client, data](void* buf) { send(client, [client, data](void* buf, size_t buf_size) -> size_t
{
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
@@ -798,9 +817,14 @@ void P2PServer::on_broadcast()
if (send_pruned) { if (send_pruned) {
LOGINFO(6, "sending BLOCK_BROADCAST (pruned) to " << log::Gray() << static_cast<char*>(client->m_addrString)); LOGINFO(6, "sending BLOCK_BROADCAST (pruned) to " << log::Gray() << static_cast<char*>(client->m_addrString));
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
const uint32_t len = static_cast<uint32_t>(data->pruned_blob.size()); const uint32_t len = static_cast<uint32_t>(data->pruned_blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@@ -811,9 +835,14 @@ void P2PServer::on_broadcast()
} }
else { else {
LOGINFO(5, "sending BLOCK_BROADCAST (full) to " << log::Gray() << static_cast<char*>(client->m_addrString)); LOGINFO(5, "sending BLOCK_BROADCAST (full) to " << log::Gray() << static_cast<char*>(client->m_addrString));
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
const uint32_t len = static_cast<uint32_t>(data->blob.size()); const uint32_t len = static_cast<uint32_t>(data->blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@@ -837,25 +866,12 @@ uint64_t P2PServer::get_random64()
void P2PServer::print_status() void P2PServer::print_status()
{ {
const int64_t uptime = seconds_since_epoch() - m_pool->start_time(); MutexLock lock(m_peerListLock);
const int64_t s = uptime % 60;
const int64_t m = (uptime / 60) % 60;
const int64_t h = (uptime / 3600) % 24;
const int64_t d = uptime / 86400;
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s1(buf);
if (d > 0) {
s1 << d << "d ";
}
s1 << h << "h " << m << "m " << s << 's';
LOGINFO(0, "status" << LOGINFO(0, "status" <<
"\nConnections = " << m_numConnections << " (" << m_numIncomingConnections << " incoming)" << "\nConnections = " << m_numConnections.load() << " (" << m_numIncomingConnections.load() << " incoming)" <<
"\nPeer list size = " << m_peerList.size() << "\nPeer list size = " << m_peerList.size() <<
"\nUptime = " << log::const_buf(buf, s1.m_pos) "\nUptime = " << log::Duration(seconds_since_epoch() - m_pool->start_time())
); );
} }
@@ -863,11 +879,16 @@ void P2PServer::show_peers()
{ {
MutexLock lock(m_clientsListLock); MutexLock lock(m_clientsListLock);
size_t n = 0;
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) { for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
if (client->m_listenPort >= 0) { if (client->m_listenPort >= 0) {
LOGINFO(0, (client->m_isIncoming ? "I " : "O ") << client->m_pingTime << " ms\t" << static_cast<char*>(client->m_addrString)); LOGINFO(0, (client->m_isIncoming ? "I " : "O ") << client->m_pingTime << " ms\t" << static_cast<char*>(client->m_addrString));
++n;
} }
} }
LOGINFO(0, "Total: " << n << " peers");
} }
void P2PServer::on_timer() void P2PServer::on_timer()
@@ -980,12 +1001,17 @@ void P2PServer::download_missing_blocks()
} }
const bool result = send(client, const bool result = send(client,
[&id](void* buf) [&id](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
memcpy(p, id.h, HASH_SIZE); memcpy(p, id.h, HASH_SIZE);
@@ -1012,6 +1038,7 @@ void P2PServer::check_zmq()
if (cur_time >= last_active + 300) { if (cur_time >= last_active + 300) {
const uint64_t dt = static_cast<uint64_t>(cur_time - last_active); const uint64_t dt = static_cast<uint64_t>(cur_time - last_active);
LOGERR(1, "no ZMQ messages received from monerod in the last " << dt << " seconds, check your monerod/p2pool/network/firewall setup!!!"); LOGERR(1, "no ZMQ messages received from monerod in the last " << dt << " seconds, check your monerod/p2pool/network/firewall setup!!!");
m_pool->restart_zmq();
} }
} }
@@ -1348,12 +1375,17 @@ bool P2PServer::P2PClient::send_handshake_challenge()
m_handshakeChallenge = owner->get_random64(); m_handshakeChallenge = owner->get_random64();
return owner->send(this, return owner->send(this,
[this, owner](void* buf) [this, owner](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending HANDSHAKE_CHALLENGE");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending HANDSHAKE_CHALLENGE");
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE); *(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE);
uint64_t k = m_handshakeChallenge; uint64_t k = m_handshakeChallenge;
@@ -1465,12 +1497,17 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
} }
const bool result = work->server->send(work->client, const bool result = work->server->send(work->client,
[work](void* buf) [work](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending HANDSHAKE_SOLUTION");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending HANDSHAKE_SOLUTION");
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION); *(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION);
memcpy(p, work->solution.h, HASH_SIZE); memcpy(p, work->solution.h, HASH_SIZE);
@@ -1615,8 +1652,14 @@ bool P2PServer::P2PClient::on_handshake_solution(const uint8_t* buf)
} }
return m_owner->send(this, return m_owner->send(this,
[this](void* buf) [this](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending LISTEN_PORT and BLOCK_REQUEST for the chain tip");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
on_after_handshake(p); on_after_handshake(p);
@@ -1679,15 +1722,21 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
} }
return server->send(this, return server->send(this,
[&blob](void* buf) [&blob](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_RESPONSE");
const uint32_t len = static_cast<uint32_t>(blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_RESPONSE");
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_RESPONSE); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_RESPONSE);
const uint32_t len = static_cast<uint32_t>(blob.size());
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@@ -1841,12 +1890,17 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
} }
return server->send(this, return server->send(this,
[&peers, num_selected_peers](void* buf) [&peers, num_selected_peers](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending PEER_LIST_RESPONSE");
if (buf_size < SEND_BUF_MIN_SIZE + 2 + num_selected_peers * 19) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending PEER_LIST_RESPONSE");
*(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE); *(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE);
*(p++) = static_cast<uint8_t>(num_selected_peers); *(p++) = static_cast<uint8_t>(num_selected_peers);
@@ -2002,12 +2056,17 @@ void P2PServer::P2PClient::post_handle_incoming_block(const uint32_t reset_count
} }
const bool result = m_owner->send(this, const bool result = m_owner->send(this,
[&id](void* buf) [&id](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
if (buf_size < SEND_BUF_MIN_SIZE + 1 + HASH_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
memcpy(p, id.h, HASH_SIZE); memcpy(p, id.h, HASH_SIZE);
+3 -3
View File
@@ -133,7 +133,7 @@ public:
void print_status() override; void print_status() override;
void show_peers(); void show_peers();
size_t peer_list_size() const { return m_peerList.size(); } size_t peer_list_size() const { MutexLock lock(m_peerListLock); return m_peerList.size(); }
uint32_t max_outgoing_peers() const { return m_maxOutgoingPeers; } uint32_t max_outgoing_peers() const { return m_maxOutgoingPeers; }
uint32_t max_incoming_peers() const { return m_maxIncomingPeers; } uint32_t max_incoming_peers() const { return m_maxIncomingPeers; }
@@ -181,7 +181,7 @@ private:
uint64_t m_peerId; uint64_t m_peerId;
uv_mutex_t m_peerListLock; mutable uv_mutex_t m_peerListLock;
struct Peer struct Peer
{ {
@@ -194,7 +194,7 @@ private:
std::vector<Peer> m_peerList; std::vector<Peer> m_peerList;
std::vector<Peer> m_peerListMonero; std::vector<Peer> m_peerListMonero;
uint64_t m_peerListLastSaved; std::atomic<uint64_t> m_peerListLastSaved;
struct Broadcast struct Broadcast
{ {
+62 -9
View File
@@ -35,6 +35,7 @@
#include "crypto.h" #include "crypto.h"
#include "p2pool_api.h" #include "p2pool_api.h"
#include "pool_block.h" #include "pool_block.h"
#include "keccak.h"
#include <thread> #include <thread>
#include <fstream> #include <fstream>
@@ -60,13 +61,13 @@ p2pool::p2pool(int argc, char* argv[])
if (!m_params->m_wallet.valid()) { if (!m_params->m_wallet.valid()) {
LOGERR(1, "Invalid wallet address. Try \"p2pool --help\"."); LOGERR(1, "Invalid wallet address. Try \"p2pool --help\".");
panic(); throw std::exception();
} }
bool is_v6; bool is_v6;
if (!resolve_host(m_params->m_host, is_v6)) { if (!resolve_host(m_params->m_host, is_v6)) {
LOGERR(1, "resolve_host failed for " << m_params->m_host); LOGERR(1, "resolve_host failed for " << m_params->m_host);
panic(); throw std::exception();
} }
hash pub, sec, eph_public_key; hash pub, sec, eph_public_key;
@@ -75,7 +76,7 @@ p2pool::p2pool(int argc, char* argv[])
uint8_t view_tag; uint8_t view_tag;
if (!m_params->m_wallet.get_eph_public_key(sec, 0, eph_public_key, view_tag)) { if (!m_params->m_wallet.get_eph_public_key(sec, 0, eph_public_key, view_tag)) {
LOGERR(1, "Invalid wallet address: get_eph_public_key failed"); LOGERR(1, "Invalid wallet address: get_eph_public_key failed");
panic(); throw std::exception();
} }
const NetworkType type = m_params->m_wallet.type(); const NetworkType type = m_params->m_wallet.type();
@@ -90,24 +91,31 @@ p2pool::p2pool(int argc, char* argv[])
int err = uv_async_init(uv_default_loop_checked(), &m_submitBlockAsync, on_submit_block); int err = uv_async_init(uv_default_loop_checked(), &m_submitBlockAsync, on_submit_block);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); throw std::exception();
} }
m_submitBlockAsync.data = this; m_submitBlockAsync.data = this;
err = uv_async_init(uv_default_loop_checked(), &m_blockTemplateAsync, on_update_block_template); err = uv_async_init(uv_default_loop_checked(), &m_blockTemplateAsync, on_update_block_template);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); throw std::exception();
} }
m_blockTemplateAsync.data = this; m_blockTemplateAsync.data = this;
err = uv_async_init(uv_default_loop_checked(), &m_stopAsync, on_stop); err = uv_async_init(uv_default_loop_checked(), &m_stopAsync, on_stop);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); throw std::exception();
} }
m_stopAsync.data = this; m_stopAsync.data = this;
err = uv_async_init(uv_default_loop_checked(), &m_restartZMQAsync, on_restart_zmq);
if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
throw std::exception();
}
m_restartZMQAsync.data = this;
uv_rwlock_init_checked(&m_mainchainLock); uv_rwlock_init_checked(&m_mainchainLock);
uv_rwlock_init_checked(&m_minerDataLock); uv_rwlock_init_checked(&m_minerDataLock);
uv_mutex_init_checked(&m_foundBlocksLock); uv_mutex_init_checked(&m_foundBlocksLock);
@@ -120,7 +128,7 @@ p2pool::p2pool(int argc, char* argv[])
if (m_params->m_localStats && !m_api) { if (m_params->m_localStats && !m_api) {
LOGERR(1, "--local-api and --stratum-api command line parameters can't be used without --data-api"); LOGERR(1, "--local-api and --stratum-api command line parameters can't be used without --data-api");
panic(); throw std::exception();
} }
m_sideChain = new SideChain(this, type, m_params->m_mini ? "mini" : nullptr); m_sideChain = new SideChain(this, type, m_params->m_mini ? "mini" : nullptr);
@@ -294,7 +302,8 @@ void p2pool::handle_miner_data(MinerData& data)
WriteLock lock(m_mainchainLock); WriteLock lock(m_mainchainLock);
for (uint64_t h = data.height; h && (h + BLOCK_HEADERS_REQUIRED > data.height); --h) { for (uint64_t h = data.height; h && (h + BLOCK_HEADERS_REQUIRED > data.height); --h) {
if (m_mainchainByHeight.find(h) == m_mainchainByHeight.end()) { auto it = m_mainchainByHeight.find(h);
if ((it == m_mainchainByHeight.end()) || it->second.difficulty.empty()) {
LOGWARN(3, "Mainchain data for height " << h << " is missing, requesting it from monerod again"); LOGWARN(3, "Mainchain data for height " << h << " is missing, requesting it from monerod again");
missing_heights.push_back(h); missing_heights.push_back(h);
} }
@@ -438,6 +447,7 @@ void p2pool::on_stop(uv_async_t* async)
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_submitBlockAsync), nullptr); uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_submitBlockAsync), nullptr);
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_blockTemplateAsync), nullptr); uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_blockTemplateAsync), nullptr);
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_stopAsync), nullptr); uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_stopAsync), nullptr);
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_restartZMQAsync), nullptr);
uv_stop(uv_default_loop()); uv_stop(uv_default_loop());
} }
@@ -632,7 +642,14 @@ void p2pool::download_block_headers(uint64_t current_height)
if (parse_block_headers_range(data, size) == current_height - start_height) { if (parse_block_headers_range(data, size) == current_height - start_height) {
update_median_timestamp(); update_median_timestamp();
if (m_serversStarted.exchange(1) == 0) { if (m_serversStarted.exchange(1) == 0) {
m_ZMQReader = new ZMQReader(m_params->m_host.c_str(), m_params->m_zmqPort, this); try {
m_ZMQReader = new ZMQReader(m_params->m_host.c_str(), m_params->m_zmqPort, this);
}
catch (const std::exception& e) {
LOGERR(1, "Couldn't start ZMQ reader: exception " << e.what());
panic();
}
m_stratumServer = new StratumServer(this); m_stratumServer = new StratumServer(this);
m_p2pServer = new P2PServer(this); m_p2pServer = new P2PServer(this);
#ifdef WITH_RANDOMX #ifdef WITH_RANDOMX
@@ -895,6 +912,8 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
void p2pool::get_miner_data() void p2pool::get_miner_data()
{ {
m_getMinerDataPending = true;
JSONRPCRequest::call(m_params->m_host.c_str(), m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}", JSONRPCRequest::call(m_params->m_host.c_str(), m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}",
[this](const char* data, size_t size) [this](const char* data, size_t size)
{ {
@@ -907,11 +926,22 @@ void p2pool::get_miner_data()
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::this_thread::sleep_for(std::chrono::milliseconds(1000));
get_miner_data(); get_miner_data();
} }
else {
m_getMinerDataPending = false;
}
}); });
} }
void p2pool::parse_get_miner_data_rpc(const char* data, size_t size) void p2pool::parse_get_miner_data_rpc(const char* data, size_t size)
{ {
hash h;
keccak(reinterpret_cast<const uint8_t*>(data), static_cast<int>(size), h.h, HASH_SIZE);
if (h == m_getMinerDataHash) {
LOGWARN(4, "Received a duplicate get_miner_data RPC response, ignoring it");
return;
}
m_getMinerDataHash = h;
rapidjson::Document doc; rapidjson::Document doc;
doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size); doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size);
@@ -1376,6 +1406,29 @@ void p2pool::stop()
uv_async_send(&m_stopAsync); uv_async_send(&m_stopAsync);
} }
void p2pool::restart_zmq()
{
if (!is_main_thread()) {
uv_async_send(&m_restartZMQAsync);
return;
}
if (!m_getMinerDataPending) {
get_miner_data();
}
delete m_ZMQReader;
m_ZMQReader = nullptr;
try {
m_ZMQReader = new ZMQReader(m_params->m_host.c_str(), m_params->m_zmqPort, this);
m_zmqLastActive = seconds_since_epoch();
}
catch (const std::exception& e) {
LOGERR(1, "Couldn't restart ZMQ reader: exception " << e.what());
}
}
int p2pool::run() int p2pool::run()
{ {
if (!m_params->ok()) { if (!m_params->ok()) {
+6
View File
@@ -95,6 +95,7 @@ public:
uint64_t zmq_last_active() const { return m_zmqLastActive; } uint64_t zmq_last_active() const { return m_zmqLastActive; }
uint64_t start_time() const { return m_startTime; } uint64_t start_time() const { return m_startTime; }
void restart_zmq();
private: private:
p2pool(const p2pool&) = delete; p2pool(const p2pool&) = delete;
@@ -103,6 +104,7 @@ private:
static void on_submit_block(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->submit_block(); } static void on_submit_block(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->submit_block(); }
static void on_update_block_template(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->update_block_template(); } static void on_update_block_template(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->update_block_template(); }
static void on_stop(uv_async_t*); static void on_stop(uv_async_t*);
static void on_restart_zmq(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->restart_zmq(); }
void submit_block() const; void submit_block() const;
@@ -197,8 +199,12 @@ private:
std::atomic<uint64_t> m_zmqLastActive; std::atomic<uint64_t> m_zmqLastActive;
uint64_t m_startTime; uint64_t m_startTime;
uv_async_t m_restartZMQAsync;
ZMQReader* m_ZMQReader = nullptr; ZMQReader* m_ZMQReader = nullptr;
hash m_getMinerDataHash;
bool m_getMinerDataPending = false;
}; };
} // namespace p2pool } // namespace p2pool
-2
View File
@@ -131,12 +131,10 @@ void p2pool_api::dump_to_file()
{ {
MutexLock lock(m_dumpDataLock); MutexLock lock(m_dumpDataLock);
data = std::move(m_dumpData); data = std::move(m_dumpData);
// cppcheck-suppress accessMoved
m_dumpData.clear(); m_dumpData.clear();
} }
for (auto& it : data) { for (auto& it : data) {
// cppcheck-suppress uninitvar
DumpFileWork* work = new DumpFileWork{ {}, {}, {}, it.first, std::move(it.second) }; DumpFileWork* work = new DumpFileWork{ {}, {}, {}, it.first, std::move(it.second) };
work->open_req.data = work; work->open_req.data = work;
work->write_req.data = work; work->write_req.data = work;
+1
View File
@@ -34,6 +34,7 @@ public:
LOCAL, LOCAL,
}; };
// cppcheck-suppress functionConst
void on_stop(); void on_stop();
template<typename T> template<typename T>
+6 -1
View File
@@ -125,10 +125,15 @@ Params::Params(int argc, char* argv[])
ok = true; ok = true;
} }
if (strcmp(argv[i], "--no-autodiff") == 0) {
m_autoDiff = false;
ok = true;
}
if (!ok) { if (!ok) {
fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]); fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]);
p2pool_usage(); p2pool_usage();
panic(); throw std::exception();
} }
} }
+1
View File
@@ -48,6 +48,7 @@ struct Params
uint32_t m_maxIncomingPeers = 1000; uint32_t m_maxIncomingPeers = 1000;
uint32_t m_minerThreads = 0; uint32_t m_minerThreads = 0;
bool m_mini = false; bool m_mini = false;
bool m_autoDiff = true;
}; };
} // namespace p2pool } // namespace p2pool
-1
View File
@@ -187,7 +187,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, SideChain& sidechai
const int sidechain_hash_offset = static_cast<int>((data - data_begin) + outputs_blob_size_diff); const int sidechain_hash_offset = static_cast<int>((data - data_begin) + outputs_blob_size_diff);
READ_BUF(m_sidechainId.h, HASH_SIZE); READ_BUF(m_sidechainId.h, HASH_SIZE);
// cppcheck-suppress duplicateExpression
if (static_cast<uint64_t>(data - tx_extra_begin) != tx_extra_size) return __LINE__; if (static_cast<uint64_t>(data - tx_extra_begin) != tx_extra_size) return __LINE__;
EXPECT_BYTE(0); EXPECT_BYTE(0);
-2
View File
@@ -180,7 +180,6 @@ void RandomX_Hasher::set_seed(const hash& seed)
} }
{ {
// cppcheck-suppress unreadVariable
ON_SCOPE_LEAVE([this]() { uv_rwlock_wrunlock(&m_cacheLock); }); ON_SCOPE_LEAVE([this]() { uv_rwlock_wrunlock(&m_cacheLock); });
if (m_stopped.load()) { if (m_stopped.load()) {
@@ -327,7 +326,6 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*
{ {
// First try to use the dataset if it's ready // First try to use the dataset if it's ready
if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) { if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) {
// cppcheck-suppress unreadVariable
ON_SCOPE_LEAVE([this]() { uv_rwlock_rdunlock(&m_datasetLock); }); ON_SCOPE_LEAVE([this]() { uv_rwlock_rdunlock(&m_datasetLock); });
if (m_stopped.load()) { if (m_stopped.load()) {
+115 -53
View File
@@ -61,6 +61,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
: m_pool(pool) : m_pool(pool)
, m_networkType(type) , m_networkType(type)
, m_chainTip{ nullptr } , m_chainTip{ nullptr }
, m_seenWalletsLastPruneTime(0)
, m_poolName(pool_name ? pool_name : "default") , m_poolName(pool_name ? pool_name : "default")
, m_targetBlockTime(10) , m_targetBlockTime(10)
, m_minDifficulty(MIN_DIFFICULTY, 0) , m_minDifficulty(MIN_DIFFICULTY, 0)
@@ -78,12 +79,12 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
panic(); panic();
} }
uv_mutex_init_checked(&m_sidechainLock); uv_rwlock_init_checked(&m_sidechainLock);
uv_mutex_init_checked(&m_seenWalletsLock);
uv_mutex_init_checked(&m_seenBlocksLock); uv_mutex_init_checked(&m_seenBlocksLock);
uv_rwlock_init_checked(&m_curDifficultyLock);
m_difficultyData.reserve(m_chainWindowSize); m_difficultyData.reserve(m_chainWindowSize);
m_tmpShares.reserve(m_chainWindowSize * 2);
m_tmpRewards.reserve(m_chainWindowSize * 2);
LOGINFO(1, "generating consensus ID"); LOGINFO(1, "generating consensus ID");
@@ -162,16 +163,18 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
SideChain::~SideChain() SideChain::~SideChain()
{ {
uv_mutex_destroy(&m_sidechainLock); uv_rwlock_destroy(&m_sidechainLock);
uv_mutex_destroy(&m_seenWalletsLock);
uv_mutex_destroy(&m_seenBlocksLock); uv_mutex_destroy(&m_seenBlocksLock);
for (auto& it : m_blocksById) { uv_rwlock_destroy(&m_curDifficultyLock);
for (const auto& it : m_blocksById) {
delete it.second; delete it.second;
} }
} }
void SideChain::fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txkeySec, std::vector<MinerShare>& shares) void SideChain::fill_sidechain_data(PoolBlock& block, const Wallet* w, const hash& txkeySec, std::vector<MinerShare>& shares) const
{ {
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
block.m_minerWallet = *w; block.m_minerWallet = *w;
block.m_txkeySec = txkeySec; block.m_txkeySec = txkeySec;
@@ -206,7 +209,11 @@ void SideChain::fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txk
} }
for (uint64_t i = 0, n = std::min<uint64_t>(UNCLE_BLOCK_DEPTH, tip->m_sidechainHeight + 1); i < n; ++i) { for (uint64_t i = 0, n = std::min<uint64_t>(UNCLE_BLOCK_DEPTH, tip->m_sidechainHeight + 1); i < n; ++i) {
for (PoolBlock* uncle : m_blocksByHeight[tip->m_sidechainHeight - i]) { auto it = m_blocksByHeight.find(tip->m_sidechainHeight - i);
if (it == m_blocksByHeight.end()) {
continue;
}
for (const PoolBlock* uncle : it->second) {
// Only add verified and valid blocks // Only add verified and valid blocks
if (!uncle || !uncle->m_verified || uncle->m_invalid) { if (!uncle || !uncle->m_verified || uncle->m_invalid) {
continue; continue;
@@ -221,16 +228,13 @@ void SideChain::fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txk
bool same_chain = false; bool same_chain = false;
do { do {
tmp = tip; tmp = tip;
while (tmp->m_sidechainHeight > uncle->m_sidechainHeight) { while (tmp && (tmp->m_sidechainHeight > uncle->m_sidechainHeight)) {
tmp = get_parent(tmp); tmp = get_parent(tmp);
if (!tmp) {
break;
}
} }
if (!tmp || (tmp->m_sidechainHeight < uncle->m_sidechainHeight)) { if (!tmp || (tmp->m_sidechainHeight < uncle->m_sidechainHeight)) {
break; break;
} }
PoolBlock* tmp2 = uncle; const PoolBlock* tmp2 = uncle;
for (size_t j = 0; (j < UNCLE_BLOCK_DEPTH) && tmp && tmp2 && (tmp->m_sidechainHeight + UNCLE_BLOCK_DEPTH >= block.m_sidechainHeight); ++j) { for (size_t j = 0; (j < UNCLE_BLOCK_DEPTH) && tmp && tmp2 && (tmp->m_sidechainHeight + UNCLE_BLOCK_DEPTH >= block.m_sidechainHeight); ++j) {
if (tmp->m_parent == tmp2->m_parent) { if (tmp->m_parent == tmp2->m_parent) {
same_chain = true; same_chain = true;
@@ -263,7 +267,7 @@ void SideChain::fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txk
block.m_uncles.erase(std::unique(block.m_uncles.begin(), block.m_uncles.end()), block.m_uncles.end()); block.m_uncles.erase(std::unique(block.m_uncles.begin(), block.m_uncles.end()), block.m_uncles.end());
} }
block.m_difficulty = m_curDifficulty; block.m_difficulty = difficulty();
block.m_cumulativeDifficulty = tip->m_cumulativeDifficulty + block.m_difficulty; block.m_cumulativeDifficulty = tip->m_cumulativeDifficulty + block.m_difficulty;
for (const hash& uncle_id : block.m_uncles) { for (const hash& uncle_id : block.m_uncles) {
@@ -395,9 +399,10 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
return false; return false;
} }
bool too_low_diff = (block.m_difficulty < m_curDifficulty); const difficulty_type expected_diff = difficulty();
bool too_low_diff = (block.m_difficulty < expected_diff);
{ {
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
if (m_blocksById.find(block.m_sidechainId) != m_blocksById.end()) { if (m_blocksById.find(block.m_sidechainId) != m_blocksById.end()) {
LOGINFO(4, "add_external_block: block " << block.m_sidechainId << " is already added"); LOGINFO(4, "add_external_block: block " << block.m_sidechainId << " is already added");
return true; return true;
@@ -423,7 +428,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
LOGINFO(4, "add_external_block: height = " << block.m_sidechainHeight << ", id = " << block.m_sidechainId << ", mainchain height = " << block.m_txinGenHeight); LOGINFO(4, "add_external_block: height = " << block.m_sidechainHeight << ", id = " << block.m_sidechainId << ", mainchain height = " << block.m_txinGenHeight);
if (too_low_diff) { if (too_low_diff) {
LOGWARN(4, "add_external_block: block has too low difficulty " << block.m_difficulty << ", expected >= ~" << m_curDifficulty << ". Ignoring it."); LOGWARN(4, "add_external_block: block has too low difficulty " << block.m_difficulty << ", expected >= ~" << expected_diff << ". Ignoring it.");
return true; return true;
} }
@@ -479,7 +484,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
missing_blocks.clear(); missing_blocks.clear();
{ {
MutexLock lock(m_sidechainLock); WriteLock lock(m_sidechainLock);
if (!block.m_parent.empty() && (m_blocksById.find(block.m_parent) == m_blocksById.end())) { if (!block.m_parent.empty() && (m_blocksById.find(block.m_parent) == m_blocksById.end())) {
missing_blocks.push_back(block.m_parent); missing_blocks.push_back(block.m_parent);
} }
@@ -520,8 +525,12 @@ void SideChain::add_block(const PoolBlock& block)
); );
PoolBlock* new_block = new PoolBlock(block); PoolBlock* new_block = new PoolBlock(block);
{
MutexLock lock(m_seenWalletsLock);
m_seenWallets[new_block->m_minerWallet.spend_public_key()] = new_block->m_localTimestamp;
}
MutexLock lock(m_sidechainLock); WriteLock lock(m_sidechainLock);
auto result = m_blocksById.insert({ new_block->m_sidechainId, new_block }); auto result = m_blocksById.insert({ new_block->m_sidechainId, new_block });
if (!result.second) { if (!result.second) {
@@ -551,13 +560,11 @@ void SideChain::add_block(const PoolBlock& block)
else { else {
verify_loop(new_block); verify_loop(new_block);
} }
m_seenWallets[new_block->m_minerWallet.spend_public_key()] = new_block->m_localTimestamp;
} }
PoolBlock* SideChain::find_block(const hash& id) PoolBlock* SideChain::find_block(const hash& id) const
{ {
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
auto it = m_blocksById.find(id); auto it = m_blocksById.find(id);
if (it != m_blocksById.end()) { if (it != m_blocksById.end()) {
@@ -569,20 +576,25 @@ PoolBlock* SideChain::find_block(const hash& id)
void SideChain::watch_mainchain_block(const ChainMain& data, const hash& possible_id) void SideChain::watch_mainchain_block(const ChainMain& data, const hash& possible_id)
{ {
MutexLock lock(m_sidechainLock); WriteLock lock(m_sidechainLock);
m_watchBlock = data; m_watchBlock = data;
m_watchBlockSidechainId = possible_id; m_watchBlockSidechainId = possible_id;
} }
bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
{ {
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
const PoolBlock* block = nullptr; const PoolBlock* block = nullptr;
// Empty hash means we return current sidechain tip // Empty hash means we return current sidechain tip
if (id == hash()) { if (id.empty()) {
block = m_chainTip; block = m_chainTip;
// Don't return stale chain tip
if (block && (block->m_txinGenHeight + 2 < m_pool->miner_data().height)) {
return false;
}
} }
else { else {
auto it = m_blocksById.find(id); auto it = m_blocksById.find(id);
@@ -602,11 +614,11 @@ bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob)
return true; return true;
} }
bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob) bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob) const
{ {
blob.clear(); blob.clear();
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
auto it = m_blocksById.find(block->m_sidechainId); auto it = m_blocksById.find(block->m_sidechainId);
if (it != m_blocksById.end()) { if (it != m_blocksById.end()) {
@@ -630,11 +642,14 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
return true; return true;
} }
if (!get_shares(block, m_tmpShares) || !split_reward(total_reward, m_tmpShares, m_tmpRewards) || (m_tmpRewards.size() != m_tmpShares.size())) { std::vector<MinerShare> tmpShares;
std::vector<uint64_t> tmpRewards;
if (!get_shares(block, tmpShares) || !split_reward(total_reward, tmpShares, tmpRewards) || (tmpRewards.size() != tmpShares.size())) {
return false; return false;
} }
const size_t n = m_tmpShares.size(); const size_t n = tmpShares.size();
blob.reserve(n * 39 + 64); blob.reserve(n * 39 + 64);
@@ -647,12 +662,12 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
hash eph_public_key; hash eph_public_key;
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
writeVarint(m_tmpRewards[i], blob); writeVarint(tmpRewards[i], blob);
blob.emplace_back(tx_type); blob.emplace_back(tx_type);
uint8_t view_tag; uint8_t view_tag;
if (!m_tmpShares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key, view_tag)) { if (!tmpShares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key, view_tag)) {
LOGWARN(6, "get_eph_public_key failed at index " << i); LOGWARN(6, "get_eph_public_key failed at index " << i);
} }
blob.insert(blob.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE); blob.insert(blob.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
@@ -661,21 +676,23 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
blob.emplace_back(view_tag); blob.emplace_back(view_tag);
} }
block->m_outputs.emplace_back(m_tmpRewards[i], eph_public_key, tx_type, view_tag); block->m_outputs.emplace_back(tmpRewards[i], eph_public_key, tx_type, view_tag);
} }
return true; return true;
} }
void SideChain::print_status() void SideChain::print_status() const
{ {
std::vector<hash> blocks_in_window; std::vector<hash> blocks_in_window;
blocks_in_window.reserve(m_chainWindowSize * 9 / 8); blocks_in_window.reserve(m_chainWindowSize * 9 / 8);
MutexLock lock(m_sidechainLock); const difficulty_type diff = difficulty();
ReadLock lock(m_sidechainLock);
uint64_t rem; uint64_t rem;
uint64_t pool_hashrate = udiv128(m_curDifficulty.hi, m_curDifficulty.lo, m_targetBlockTime, &rem); uint64_t pool_hashrate = udiv128(diff.hi, diff.lo, m_targetBlockTime, &rem);
difficulty_type network_diff = m_pool->miner_data().difficulty; difficulty_type network_diff = m_pool->miner_data().difficulty;
uint64_t network_hashrate = udiv128(network_diff.hi, network_diff.lo, 120, &rem); uint64_t network_hashrate = udiv128(network_diff.hi, network_diff.lo, 120, &rem);
@@ -736,7 +753,11 @@ void SideChain::print_status()
if (tip) { if (tip) {
std::sort(blocks_in_window.begin(), blocks_in_window.end()); std::sort(blocks_in_window.begin(), blocks_in_window.end());
for (uint64_t i = 0; (i < m_chainWindowSize) && (i <= tip_height); ++i) { for (uint64_t i = 0; (i < m_chainWindowSize) && (i <= tip_height); ++i) {
for (PoolBlock* block : m_blocksByHeight[tip_height - i]) { auto it = m_blocksByHeight.find(tip_height - i);
if (it == m_blocksByHeight.end()) {
continue;
}
for (const PoolBlock* block : it->second) {
if (!std::binary_search(blocks_in_window.begin(), blocks_in_window.end(), block->m_sidechainId)) { if (!std::binary_search(blocks_in_window.begin(), blocks_in_window.end(), block->m_sidechainId)) {
LOGINFO(4, "orphan block at height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << ": " << log::Gray() << block->m_sidechainId); LOGINFO(4, "orphan block at height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << ": " << log::Gray() << block->m_sidechainId);
++total_orphans; ++total_orphans;
@@ -747,7 +768,7 @@ void SideChain::print_status()
} }
} }
Wallet w = m_pool->params().m_wallet; const Wallet& w = m_pool->params().m_wallet;
hash eph_public_key; hash eph_public_key;
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) { for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
@@ -811,6 +832,38 @@ void SideChain::print_status()
); );
} }
double SideChain::get_reward_share(const Wallet& w) const
{
uint64_t reward = 0;
uint64_t total_reward = 0;
{
ReadLock lock(m_sidechainLock);
const PoolBlock* tip = m_chainTip;
if (tip) {
hash eph_public_key;
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
const PoolBlock::TxOutput& out = tip->m_outputs[i];
if (!reward) {
if (out.m_txType == TXOUT_TO_TAGGED_KEY) {
if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) {
reward = out.m_reward;
}
}
else {
uint8_t view_tag;
if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag) && (out.m_ephPublicKey == eph_public_key)) {
reward = out.m_reward;
}
}
}
total_reward += out.m_reward;
}
}
}
return total_reward ? (static_cast<double>(reward) / static_cast<double>(total_reward)) : 0.0;
}
difficulty_type SideChain::total_hashes() const difficulty_type SideChain::total_hashes() const
{ {
const PoolBlock* tip = m_chainTip; const PoolBlock* tip = m_chainTip;
@@ -821,16 +874,19 @@ uint64_t SideChain::miner_count()
{ {
const uint64_t cur_time = seconds_since_epoch(); const uint64_t cur_time = seconds_since_epoch();
MutexLock lock(m_sidechainLock); MutexLock lock(m_seenWalletsLock);
// Delete wallets that weren't seen for more than 72 hours and return how many remain // Every 5 minutes, delete wallets that weren't seen for more than 72 hours
for (auto it = m_seenWallets.begin(); it != m_seenWallets.end();) { if (m_seenWalletsLastPruneTime + 5 * 60 <= cur_time) {
if (it->second + 72 * 60 * 60 <= cur_time) { for (auto it = m_seenWallets.begin(); it != m_seenWallets.end();) {
it = m_seenWallets.erase(it); if (it->second + 72 * 60 * 60 < cur_time) {
} it = m_seenWallets.erase(it);
else { }
++it; else {
++it;
}
} }
m_seenWalletsLastPruneTime = cur_time;
} }
return m_seenWallets.size(); return m_seenWallets.size();
@@ -1405,10 +1461,13 @@ void SideChain::update_chain_tip(PoolBlock* block)
difficulty_type diff; difficulty_type diff;
if (get_difficulty(block, m_difficultyData, diff)) { if (get_difficulty(block, m_difficultyData, diff)) {
m_chainTip = block; m_chainTip = block;
m_curDifficulty = diff; {
WriteLock lock(m_curDifficultyLock);
m_curDifficulty = diff;
}
LOGINFO(2, "new chain tip: next height = " << log::Gray() << block->m_sidechainHeight + 1 << log::NoColor() << LOGINFO(2, "new chain tip: next height = " << log::Gray() << block->m_sidechainHeight + 1 << log::NoColor() <<
", next difficulty = " << log::Gray() << m_curDifficulty << log::NoColor() << ", next difficulty = " << log::Gray() << diff << log::NoColor() <<
", main chain height = " << log::Gray() << block->m_txinGenHeight); ", main chain height = " << log::Gray() << block->m_txinGenHeight);
block->m_wantBroadcast = true; block->m_wantBroadcast = true;
@@ -1419,6 +1478,7 @@ void SideChain::update_chain_tip(PoolBlock* block)
StratumServer* s = m_pool->stratum_server(); StratumServer* s = m_pool->stratum_server();
if (s && is_alternative) { if (s && is_alternative) {
s->reset_share_counters(); s->reset_share_counters();
LOGINFO(0, log::LightCyan() << "SYNCHRONIZED");
} }
} }
prune_old_blocks(); prune_old_blocks();
@@ -1471,7 +1531,7 @@ void SideChain::update_chain_tip(PoolBlock* block)
} }
} }
PoolBlock* SideChain::get_parent(const PoolBlock* block) PoolBlock* SideChain::get_parent(const PoolBlock* block) const
{ {
if (block) { if (block) {
auto it = m_blocksById.find(block->m_parent); auto it = m_blocksById.find(block->m_parent);
@@ -1491,13 +1551,15 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida
} }
if (!block) { if (!block) {
// Switching from an empty to a non-empty chain
is_alternative = true;
return true; return true;
} }
// If these two blocks are on the same chain, they must have a common ancestor // If these two blocks are on the same chain, they must have a common ancestor
const PoolBlock* block_ancestor = block; const PoolBlock* block_ancestor = block;
while (block_ancestor->m_sidechainHeight > candidate->m_sidechainHeight) { while (block_ancestor && (block_ancestor->m_sidechainHeight > candidate->m_sidechainHeight)) {
const hash& id = block_ancestor->m_parent; const hash& id = block_ancestor->m_parent;
block_ancestor = get_parent(block_ancestor); block_ancestor = get_parent(block_ancestor);
if (!block_ancestor) { if (!block_ancestor) {
@@ -1701,11 +1763,11 @@ void SideChain::prune_old_blocks()
} }
} }
void SideChain::get_missing_blocks(std::vector<hash>& missing_blocks) void SideChain::get_missing_blocks(std::vector<hash>& missing_blocks) const
{ {
missing_blocks.clear(); missing_blocks.clear();
MutexLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
for (auto& b : m_blocksById) { for (auto& b : m_blocksById) {
if (b.second->m_verified) { if (b.second->m_verified) {
+14 -11
View File
@@ -43,21 +43,22 @@ public:
SideChain(p2pool* pool, NetworkType type, const char* pool_name = nullptr); SideChain(p2pool* pool, NetworkType type, const char* pool_name = nullptr);
~SideChain(); ~SideChain();
void fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txkeySec, std::vector<MinerShare>& shares); void fill_sidechain_data(PoolBlock& block, const Wallet* w, const hash& txkeySec, std::vector<MinerShare>& shares) const;
bool block_seen(const PoolBlock& block); bool block_seen(const PoolBlock& block);
void unsee_block(const PoolBlock& block); void unsee_block(const PoolBlock& block);
bool add_external_block(PoolBlock& block, std::vector<hash>& missing_blocks); bool add_external_block(PoolBlock& block, std::vector<hash>& missing_blocks);
void add_block(const PoolBlock& block); void add_block(const PoolBlock& block);
void get_missing_blocks(std::vector<hash>& missing_blocks); void get_missing_blocks(std::vector<hash>& missing_blocks) const;
PoolBlock* find_block(const hash& id); PoolBlock* find_block(const hash& id) const;
void watch_mainchain_block(const ChainMain& data, const hash& possible_id); void watch_mainchain_block(const ChainMain& data, const hash& possible_id);
bool get_block_blob(const hash& id, std::vector<uint8_t>& blob); bool get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
bool get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob); bool get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob) const;
void print_status(); void print_status() const;
double get_reward_share(const Wallet& w) const;
// Consensus ID can be used to spawn independent P2Pools with their own sidechains // Consensus ID can be used to spawn independent P2Pools with their own sidechains
// It's never sent over the network to avoid revealing it to the possible man in the middle // It's never sent over the network to avoid revealing it to the possible man in the middle
@@ -65,7 +66,7 @@ public:
const std::vector<uint8_t>& consensus_id() const { return m_consensusId; } const std::vector<uint8_t>& consensus_id() const { return m_consensusId; }
uint64_t chain_window_size() const { return m_chainWindowSize; } uint64_t chain_window_size() const { return m_chainWindowSize; }
NetworkType network_type() const { return m_networkType; } NetworkType network_type() const { return m_networkType; }
const difficulty_type& difficulty() const { return m_curDifficulty; } FORCEINLINE difficulty_type difficulty() const { ReadLock lock(m_curDifficultyLock); return m_curDifficulty; }
difficulty_type total_hashes() const; difficulty_type total_hashes() const;
uint64_t block_time() const { return m_targetBlockTime; } uint64_t block_time() const { return m_targetBlockTime; }
uint64_t miner_count(); uint64_t miner_count();
@@ -88,7 +89,7 @@ private:
void verify_loop(PoolBlock* block); void verify_loop(PoolBlock* block);
void verify(PoolBlock* block); void verify(PoolBlock* block);
void update_chain_tip(PoolBlock* block); void update_chain_tip(PoolBlock* block);
PoolBlock* get_parent(const PoolBlock* block); PoolBlock* get_parent(const PoolBlock* block) const;
// Checks if "candidate" has longer (higher difficulty) chain than "block" // Checks if "candidate" has longer (higher difficulty) chain than "block"
bool is_longer_chain(const PoolBlock* block, const PoolBlock* candidate, bool& is_alternative); bool is_longer_chain(const PoolBlock* block, const PoolBlock* candidate, bool& is_alternative);
@@ -98,13 +99,14 @@ private:
bool load_config(const std::string& filename); bool load_config(const std::string& filename);
bool check_config(); bool check_config();
mutable uv_mutex_t m_sidechainLock; mutable uv_rwlock_t m_sidechainLock;
std::atomic<PoolBlock*> m_chainTip; std::atomic<PoolBlock*> m_chainTip;
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight; std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
unordered_map<hash, PoolBlock*> m_blocksById; unordered_map<hash, PoolBlock*> m_blocksById;
uv_mutex_t m_seenWalletsLock;
unordered_map<hash, uint64_t> m_seenWallets; unordered_map<hash, uint64_t> m_seenWallets;
std::vector<MinerShare> m_tmpShares; uint64_t m_seenWalletsLastPruneTime;
std::vector<uint64_t> m_tmpRewards;
uv_mutex_t m_seenBlocksLock; uv_mutex_t m_seenBlocksLock;
unordered_set<hash> m_seenBlocks; unordered_set<hash> m_seenBlocks;
@@ -121,6 +123,7 @@ private:
std::vector<uint8_t> m_consensusId; std::vector<uint8_t> m_consensusId;
std::string m_consensusIdDisplayStr; std::string m_consensusIdDisplayStr;
mutable uv_rwlock_t m_curDifficultyLock;
difficulty_type m_curDifficulty; difficulty_type m_curDifficulty;
ChainMain m_watchBlock; ChainMain m_watchBlock;
+231 -84
View File
@@ -27,9 +27,11 @@ static constexpr char log_category_prefix[] = "StratumServer ";
static constexpr int DEFAULT_BACKLOG = 128; static constexpr int DEFAULT_BACKLOG = 128;
static constexpr uint64_t DEFAULT_BAN_TIME = 600; static constexpr uint64_t DEFAULT_BAN_TIME = 600;
static constexpr uint64_t MIN_DIFF = 1000;
static constexpr uint64_t AUTO_DIFF_TARGET_TIME = 30;
// Use short target format (4 bytes) for diff <= 4 million // Use short target format (4 bytes) for diff <= 4 million
static constexpr uint64_t TARGET_4_BYTES_LIMIT = std::numeric_limits<uint64_t>::max() / 4000000; static constexpr uint64_t TARGET_4_BYTES_LIMIT = std::numeric_limits<uint64_t>::max() / 4000000 + 1;
#include "tcp_server.inl" #include "tcp_server.inl"
@@ -38,6 +40,7 @@ namespace p2pool {
StratumServer::StratumServer(p2pool* pool) StratumServer::StratumServer(p2pool* pool)
: TCPServer(StratumClient::allocate) : TCPServer(StratumClient::allocate)
, m_pool(pool) , m_pool(pool)
, m_autoDiff(pool->params().m_autoDiff)
, m_extraNonce(0) , m_extraNonce(0)
, m_rng(RandomDeviceSeed::instance) , m_rng(RandomDeviceSeed::instance)
, m_cumulativeHashes(0) , m_cumulativeHashes(0)
@@ -57,7 +60,6 @@ StratumServer::StratumServer(p2pool* pool)
uv_mutex_init_checked(&m_blobsQueueLock); uv_mutex_init_checked(&m_blobsQueueLock);
uv_mutex_init_checked(&m_rngLock); uv_mutex_init_checked(&m_rngLock);
uv_mutex_init_checked(&m_submittedSharesPoolLock);
uv_rwlock_init_checked(&m_hashrateDataLock); uv_rwlock_init_checked(&m_hashrateDataLock);
m_submittedSharesPool.resize(10); m_submittedSharesPool.resize(10);
@@ -68,7 +70,7 @@ StratumServer::StratumServer(p2pool* pool)
const int err = uv_async_init(&m_loop, &m_blobsAsync, on_blobs_ready); const int err = uv_async_init(&m_loop, &m_blobsAsync, on_blobs_ready);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
return; panic();
} }
m_blobsAsync.data = this; m_blobsAsync.data = this;
m_blobsQueue.reserve(2); m_blobsQueue.reserve(2);
@@ -84,7 +86,6 @@ StratumServer::~StratumServer()
uv_mutex_destroy(&m_blobsQueueLock); uv_mutex_destroy(&m_blobsQueueLock);
uv_mutex_destroy(&m_rngLock); uv_mutex_destroy(&m_rngLock);
uv_mutex_destroy(&m_submittedSharesPoolLock);
uv_rwlock_destroy(&m_hashrateDataLock); uv_rwlock_destroy(&m_hashrateDataLock);
for (SubmittedShare* share : m_submittedSharesPool) { for (SubmittedShare* share : m_submittedSharesPool) {
@@ -101,6 +102,7 @@ void StratumServer::on_block(const BlockTemplate& block)
LOGINFO(4, "no clients connected"); LOGINFO(4, "no clients connected");
return; return;
} }
m_extraNonce.exchange(num_connections);
BlobsData* blobs_data = new BlobsData{}; BlobsData* blobs_data = new BlobsData{};
@@ -112,9 +114,7 @@ void StratumServer::on_block(const BlockTemplate& block)
// Even if they do, they'll be added to the beginning of the list and will get their block template in on_login() // Even if they do, they'll be added to the beginning of the list and will get their block template in on_login()
// We'll iterate through the list backwards so when we get to the beginning and run out of extra_nonce values, it'll be only new clients left // We'll iterate through the list backwards so when we get to the beginning and run out of extra_nonce values, it'll be only new clients left
blobs_data->m_numClientsExpected = num_connections; blobs_data->m_numClientsExpected = num_connections;
m_extraNonce.exchange(blobs_data->m_numClientsExpected); blobs_data->m_blobSize = block.get_hashing_blobs(0, num_connections, blobs_data->m_blobs, blobs_data->m_height, difficulty, sidechain_difficulty, blobs_data->m_seedHash, nonce_offset, blobs_data->m_templateId);
blobs_data->m_blobSize = block.get_hashing_blobs(0, blobs_data->m_numClientsExpected, blobs_data->m_blobs, blobs_data->m_height, difficulty, sidechain_difficulty, blobs_data->m_seedHash, nonce_offset, blobs_data->m_templateId);
// Integrity checks // Integrity checks
if (blobs_data->m_blobSize < 76) { if (blobs_data->m_blobSize < 76) {
@@ -178,11 +178,13 @@ void StratumServer::on_block(const BlockTemplate& block)
} }
} }
bool StratumServer::get_custom_user(const char* s, std::string& user) template<size_t N>
static bool get_custom_user(const char* s, char (&user)[N])
{ {
user.clear(); size_t len = 0;
// Find first of '+' or '.', drop non-printable characters // Find first of '+' or '.', drop non-printable characters
while (s && (user.length() < 64)) { while (s && (len < N - 1)) {
const char c = *s; const char c = *s;
if (!c) { if (!c) {
break; break;
@@ -192,15 +194,16 @@ bool StratumServer::get_custom_user(const char* s, std::string& user)
} }
// Limit to printable ASCII characters // Limit to printable ASCII characters
if (c >= ' ' && c <= '~') { if (c >= ' ' && c <= '~') {
user += c; user[len++] = c;
} }
++s; ++s;
} }
user[len] = '\0';
return !user.empty(); return (len > 0);
} }
bool StratumServer::get_custom_diff(const char* s, difficulty_type& diff) static bool get_custom_diff(const char* s, difficulty_type& diff)
{ {
const char* diff_str = nullptr; const char* diff_str = nullptr;
@@ -219,8 +222,8 @@ bool StratumServer::get_custom_diff(const char* s, difficulty_type& diff)
if (diff_str) { if (diff_str) {
const uint64_t t = strtoull(diff_str + 1, nullptr, 10); const uint64_t t = strtoull(diff_str + 1, nullptr, 10);
if (t) { if (t) {
// Don't let clients set difficulty less than 1000 // Don't let clients set difficulty less than MIN_DIFF
diff = { std::max<uint64_t>(t + 1, 1000), 0 }; diff = { std::max<uint64_t>(t + 1, MIN_DIFF), 0 };
return true; return true;
} }
} }
@@ -250,16 +253,15 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
} }
if (get_custom_user(login, client->m_customUser)) { if (get_custom_user(login, client->m_customUser)) {
LOGINFO(5, "client " << log::Gray() << static_cast<char*>(client->m_addrString) << " set custom user " << client->m_customUser); const char* s = client->m_customUser;
LOGINFO(5, "client " << log::Gray() << static_cast<char*>(client->m_addrString) << " set custom user " << s);
} }
uint32_t job_id; uint32_t job_id;
{ {
MutexLock lock(client->m_jobsLock); job_id = ++client->m_perConnectionJobId;
job_id = client->m_perConnectionJobId++; StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
saved_job.job_id = job_id; saved_job.job_id = job_id;
saved_job.extra_nonce = extra_nonce; saved_job.extra_nonce = extra_nonce;
saved_job.template_id = template_id; saved_job.template_id = template_id;
@@ -267,7 +269,7 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
} }
const bool result = send(client, const bool result = send(client,
[client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](void* buf) [client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](void* buf, size_t buf_size)
{ {
do { do {
client->m_rpcId = static_cast<uint32_t>(static_cast<StratumServer*>(client->m_owner)->get_random64()); client->m_rpcId = static_cast<uint32_t>(static_cast<StratumServer*>(client->m_owner)->get_random64());
@@ -280,7 +282,7 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
target_hex.m_size -= sizeof(uint32_t); target_hex.m_size -= sizeof(uint32_t);
} }
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"result\":{\"id\":\""; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"";
s << log::Hex(client->m_rpcId) << "\",\"job\":{\"blob\":\""; s << log::Hex(client->m_rpcId) << "\",\"job\":{\"blob\":\"";
s << log::hex_buf(hashing_blob, blob_size) << "\",\"job_id\":\""; s << log::hex_buf(hashing_blob, blob_size) << "\",\"job_id\":\"";
@@ -307,6 +309,11 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
job_id = (job_id << 4) + d; job_id = (job_id << 4) + d;
} }
if (!job_id) {
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " invalid params ('job_id' can't be 0)");
return false;
}
uint32_t nonce = 0; uint32_t nonce = 0;
for (int i = static_cast<int>(sizeof(uint32_t)) - 1; i >= 0; --i) { for (int i = static_cast<int>(sizeof(uint32_t)) - 1; i >= 0; --i) {
@@ -335,9 +342,7 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
bool found = false; bool found = false;
{ {
MutexLock lock(client->m_jobsLock); const StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
const StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
if (saved_job.job_id == job_id) { if (saved_job.job_id == job_id) {
template_id = saved_job.template_id; template_id = saved_job.template_id;
extra_nonce = saved_job.extra_nonce; extra_nonce = saved_job.extra_nonce;
@@ -353,33 +358,33 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
if (!block.get_difficulties(template_id, mainchain_diff, sidechain_diff)) { if (!block.get_difficulties(template_id, mainchain_diff, sidechain_diff)) {
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share"); LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share");
return send(client, return send(client,
[id](void* buf) [id](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n"; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n";
return s.m_pos; return s.m_pos;
}); });
} }
if (mainchain_diff.check_pow(resultHash)) { if (mainchain_diff.check_pow(resultHash)) {
const std::string& s = client->m_customUser; const char* s = client->m_customUser;
LOGINFO(0, log::Green() << "client " << static_cast<char*>(client->m_addrString) << (!s.empty() ? " user " : "") << s << " found a mainchain block, submitting it"); LOGINFO(0, log::Green() << "client " << static_cast<char*>(client->m_addrString) << (*s ? " user " : "") << s << " found a mainchain block, submitting it");
m_pool->submit_block_async(template_id, nonce, extra_nonce); m_pool->submit_block_async(template_id, nonce, extra_nonce);
block.update_tx_keys(); block.update_tx_keys();
} }
SubmittedShare* share; SubmittedShare* share;
{ if (!m_submittedSharesPool.empty()) {
MutexLock lock(m_submittedSharesPoolLock); share = m_submittedSharesPool.back();
m_submittedSharesPool.pop_back();
}
else {
share = new SubmittedShare{};
}
if (!m_submittedSharesPool.empty()) { if (target >= TARGET_4_BYTES_LIMIT) {
share = m_submittedSharesPool.back(); target = (target >> 32) << 32;
m_submittedSharesPool.pop_back();
}
else {
share = new SubmittedShare{};
}
} }
share->m_req.data = share; share->m_req.data = share;
@@ -395,9 +400,16 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
share->m_target = target; share->m_target = target;
share->m_resultHash = resultHash; share->m_resultHash = resultHash;
share->m_sidechainDifficulty = sidechain_diff; share->m_sidechainDifficulty = sidechain_diff;
share->m_timestamp = seconds_since_epoch();
uint64_t rem;
share->m_hashes = (target > 1) ? udiv128(1, 0, target, &rem) : 1;
share->m_highEnoughDifficulty = sidechain_diff.check_pow(resultHash);
update_auto_diff(client, share->m_timestamp, share->m_hashes);
// If this share is below sidechain difficulty, process it in this thread because it'll be quick // If this share is below sidechain difficulty, process it in this thread because it'll be quick
if (!share->m_sidechainDifficulty.check_pow(share->m_resultHash)) { if (!share->m_highEnoughDifficulty) {
on_share_found(&share->m_req); on_share_found(&share->m_req);
on_after_share_found(&share->m_req, 0); on_after_share_found(&share->m_req, 0);
return true; return true;
@@ -419,9 +431,9 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a share with invalid job id"); LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a share with invalid job id");
const bool result = send(client, const bool result = send(client,
[id](void* buf) [id](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Invalid job id\"}}\n"; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Invalid job id\"}}\n";
return s.m_pos; return s.m_pos;
}); });
@@ -441,8 +453,53 @@ void StratumServer::print_status()
print_stratum_status(); print_stratum_status();
} }
void StratumServer::show_workers()
{
const uint64_t cur_time = seconds_since_epoch();
const difficulty_type pool_diff = m_pool->side_chain().difficulty();
MutexLock lock(m_clientsListLock);
int addr_len = 0;
for (const StratumClient* c = static_cast<StratumClient*>(m_connectedClientsList->m_next); c != m_connectedClientsList; c = static_cast<StratumClient*>(c->m_next)) {
addr_len = std::max(addr_len, static_cast<int>(strlen(c->m_addrString)));
}
size_t n = 0;
LOGINFO(0, log::pad_right("IP:port", addr_len + 8)
<< log::pad_right("uptime", 20)
<< log::pad_right("difficulty", 20)
<< log::pad_right("hashrate", 15)
<< "name"
);
for (const StratumClient* c = static_cast<StratumClient*>(m_connectedClientsList->m_next); c != m_connectedClientsList; c = static_cast<StratumClient*>(c->m_next)) {
difficulty_type diff;
if (c->m_customDiff != 0) {
diff = c->m_customDiff;
}
else if (m_autoDiff && (c->m_autoDiff != 0)) {
diff = c->m_autoDiff;
}
else {
diff = pool_diff;
}
LOGINFO(0, log::pad_right(static_cast<const char*>(c->m_addrString), addr_len + 8)
<< log::pad_right(log::Duration(cur_time - c->m_connectedTime), 20)
<< log::pad_right(diff, 20)
<< log::pad_right(log::Hashrate(c->m_autoDiff.lo / AUTO_DIFF_TARGET_TIME, m_autoDiff && (c->m_autoDiff != 0)), 15)
<< (c->m_rpcId ? c->m_customUser : "not logged in")
);
++n;
}
LOGINFO(0, "Total: " << n << " workers");
}
void StratumServer::reset_share_counters() void StratumServer::reset_share_counters()
{ {
m_cumulativeHashes = 0;
m_cumulativeHashesAtLastShare = 0; m_cumulativeHashesAtLastShare = 0;
m_cumulativeFoundSharesDiff = 0.0; m_cumulativeFoundSharesDiff = 0.0;
m_totalFoundShares = 0; m_totalFoundShares = 0;
@@ -495,10 +552,83 @@ void StratumServer::print_stratum_status() const
"\nShares found = " << m_totalFoundShares << "\nShares found = " << m_totalFoundShares <<
"\nAverage effort = " << average_effort << '%' << "\nAverage effort = " << average_effort << '%' <<
"\nCurrent effort = " << static_cast<double>(hashes_since_last_share) * 100.0 / m_pool->side_chain().difficulty().to_double() << '%' << "\nCurrent effort = " << static_cast<double>(hashes_since_last_share) * 100.0 / m_pool->side_chain().difficulty().to_double() << '%' <<
"\nConnections = " << m_numConnections << " (" << m_numIncomingConnections << " incoming)" "\nConnections = " << m_numConnections.load() << " (" << m_numIncomingConnections.load() << " incoming)"
); );
} }
// Compresses 64-bit hashes value into 16-bit value (5 bits for shift, 11 bits for data)
namespace {
enum HashValue : uint64_t {
bits = 11,
mask = (1 << bits) - 1,
};
static constexpr FORCEINLINE uint64_t hash_uncompress(uint64_t h)
{
return (h & HashValue::mask) << (h >> HashValue::bits);
};
enum HashMaxValue : uint64_t {
value = hash_uncompress(std::numeric_limits<uint16_t>::max())
};
static FORCEINLINE uint16_t hash_compress(uint64_t h)
{
if (h <= HashValue::mask) {
return static_cast<uint16_t>(h);
}
if (h >= HashMaxValue::value) {
return std::numeric_limits<uint16_t>::max();
}
const uint64_t shift = bsr(h) - (HashValue::bits - 1);
return static_cast<uint16_t>((shift << HashValue::bits) | (h >> shift));
}
}
void StratumServer::update_auto_diff(StratumClient* client, const uint64_t timestamp, const uint64_t hashes)
{
const uint16_t hashes_compressed = hash_compress(hashes);
client->m_autoDiffWindowHashes += hash_uncompress(hashes_compressed);
const uint32_t k = client->m_autoDiffIndex++;
constexpr uint32_t N = StratumClient::AUTO_DIFF_SIZE;
StratumClient::AutoDiffData& auto_diff_data = client->m_autoDiffData[k % N];
if (k >= N) {
client->m_autoDiffWindowHashes -= hash_uncompress(auto_diff_data.m_hashes);
}
const uint16_t t1 = auto_diff_data.m_timestamp;
const uint16_t t2 = static_cast<uint16_t>(timestamp);
auto_diff_data.m_timestamp = t2;
auto_diff_data.m_hashes = hashes_compressed;
if (k >= N) {
// Full window
const uint64_t dt = t2 - t1;
client->m_autoDiff.lo = std::max<uint64_t>((client->m_autoDiffWindowHashes * AUTO_DIFF_TARGET_TIME) / (dt ? dt : 1), MIN_DIFF);
client->m_autoDiff.hi = 0;
}
else if (k >= 10) {
// Partial window
const uint64_t h0 = hash_uncompress(client->m_autoDiffData[0].m_hashes);
const uint64_t dt = client->m_autoDiffData[k].m_timestamp - client->m_autoDiffData[0].m_timestamp;
client->m_autoDiff.lo = std::max<uint64_t>(((client->m_autoDiffWindowHashes - h0) * AUTO_DIFF_TARGET_TIME) / (dt ? dt : 1), MIN_DIFF);
client->m_autoDiff.hi = 0;
}
else if (k == 0) {
// First share, fix auto diff to current difficulty until we have at least 10 shares
client->m_autoDiff.lo = hashes;
client->m_autoDiff.hi = 0;
}
}
void StratumServer::on_blobs_ready() void StratumServer::on_blobs_ready()
{ {
std::vector<BlobsData*> blobs_queue; std::vector<BlobsData*> blobs_queue;
@@ -555,14 +685,32 @@ void StratumServer::on_blobs_ready()
if (client->m_customDiff.lo) { if (client->m_customDiff.lo) {
target = std::max(target, client->m_customDiff.target()); target = std::max(target, client->m_customDiff.target());
} }
else if (m_autoDiff) {
if (client->m_autoDiff.lo) {
const uint32_t k = client->m_autoDiffIndex;
const uint16_t elapsed_time = static_cast<uint16_t>(cur_time) - client->m_autoDiffData[(k - 1) % StratumClient::AUTO_DIFF_SIZE].m_timestamp;
if (elapsed_time > AUTO_DIFF_TARGET_TIME * 5) {
// More than 500% effort, reduce the auto diff by 1/8 every time until the share is found
client->m_autoDiff.lo = std::max<uint64_t>(client->m_autoDiff.lo - client->m_autoDiff.lo / 8, MIN_DIFF);
}
target = std::max(target, client->m_autoDiff.target());
}
else {
// Not enough shares from the client yet, cut diff in half every 16 seconds
const uint64_t num_halvings = (cur_time - client->m_connectedTime) / 16;
constexpr uint64_t max_target = (std::numeric_limits<uint64_t>::max() / MIN_DIFF) + 1;
for (uint64_t i = 0; (i < num_halvings) && (target < max_target); ++i) {
target *= 2;
}
target = std::min<uint64_t>(target, max_target);
}
}
uint32_t job_id; uint32_t job_id;
{ {
MutexLock lock3(client->m_jobsLock); job_id = ++client->m_perConnectionJobId;
job_id = client->m_perConnectionJobId++; StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
saved_job.job_id = job_id; saved_job.job_id = job_id;
saved_job.extra_nonce = extra_nonce; saved_job.extra_nonce = extra_nonce;
saved_job.template_id = data->m_templateId; saved_job.template_id = data->m_templateId;
@@ -570,7 +718,7 @@ void StratumServer::on_blobs_ready()
} }
const bool result = send(client, const bool result = send(client,
[data, target, hashing_blob, &job_id](void* buf) [data, target, hashing_blob, &job_id](void* buf, size_t buf_size)
{ {
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t)); log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
@@ -579,7 +727,7 @@ void StratumServer::on_blobs_ready()
target_hex.m_size -= sizeof(uint32_t); target_hex.m_size -= sizeof(uint32_t);
} }
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\""; s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\"";
s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\""; s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\"";
s << log::Hex(job_id) << "\",\"target\":\""; s << log::Hex(job_id) << "\",\"target\":\"";
@@ -597,8 +745,9 @@ void StratumServer::on_blobs_ready()
} }
} }
if (numClientsProcessed != m_numConnections) { const uint32_t num_connections = m_numConnections;
LOGWARN(1, "client list is broken, expected " << m_numConnections << ", got " << numClientsProcessed << " clients"); if (numClientsProcessed != num_connections) {
LOGWARN(1, "client list is broken, expected " << num_connections << ", got " << numClientsProcessed << " clients");
} }
} }
@@ -638,26 +787,23 @@ void StratumServer::update_hashrate_data(uint64_t hashes, uint64_t timestamp)
void StratumServer::on_share_found(uv_work_t* req) void StratumServer::on_share_found(uv_work_t* req)
{ {
bkg_jobs_tracker.start("StratumServer::on_share_found");
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data); SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
if (share->m_highEnoughDifficulty) {
bkg_jobs_tracker.start("StratumServer::on_share_found");
}
StratumClient* client = share->m_client; StratumClient* client = share->m_client;
StratumServer* server = share->m_server; StratumServer* server = share->m_server;
p2pool* pool = server->m_pool; p2pool* pool = server->m_pool;
uint64_t target = share->m_target; const uint64_t target = share->m_target;
if (target >= TARGET_4_BYTES_LIMIT) { const uint64_t hashes = share->m_hashes;
target = (target >> 32) << 32;
}
uint64_t rem;
const uint64_t hashes = (target > 1) ? udiv128(1, 0, target, &rem) : 0;
if (pool->stopped()) { if (pool->stopped()) {
LOGWARN(0, "p2pool is shutting down, but a share was found. Trying to process it anyway!"); LOGWARN(0, "p2pool is shutting down, but a share was found. Trying to process it anyway!");
} }
if (share->m_sidechainDifficulty.check_pow(share->m_resultHash)) { if (share->m_highEnoughDifficulty) {
uint8_t blob[128]; uint8_t blob[128];
uint64_t height; uint64_t height;
difficulty_type difficulty; difficulty_type difficulty;
@@ -698,8 +844,8 @@ void StratumServer::on_share_found(uv_work_t* req)
server->m_cumulativeFoundSharesDiff += diff; server->m_cumulativeFoundSharesDiff += diff;
++server->m_totalFoundShares; ++server->m_totalFoundShares;
const std::string& s = client->m_customUser; const char* s = client->m_customUser;
LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << height << ", diff " << sidechain_difficulty << ", client " << static_cast<char*>(client->m_addrString) << (!s.empty() ? " user " : "") << s << ", effort " << effort << '%'); LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << height << ", diff " << sidechain_difficulty << ", client " << static_cast<char*>(client->m_addrString) << (*s ? " user " : "") << s << ", effort " << effort << '%');
pool->submit_sidechain_block(share->m_templateId, share->m_nonce, share->m_extraNonce); pool->submit_sidechain_block(share->m_templateId, share->m_nonce, share->m_extraNonce);
} }
@@ -707,7 +853,7 @@ void StratumServer::on_share_found(uv_work_t* req)
const uint64_t value = *reinterpret_cast<uint64_t*>(share->m_resultHash.h + HASH_SIZE - sizeof(uint64_t)); const uint64_t value = *reinterpret_cast<uint64_t*>(share->m_resultHash.h + HASH_SIZE - sizeof(uint64_t));
if (LIKELY(value < target)) { if (LIKELY(value < target)) {
const uint64_t timestamp = seconds_since_epoch(); const uint64_t timestamp = share->m_timestamp;
server->update_hashrate_data(hashes, timestamp); server->update_hashrate_data(hashes, timestamp);
server->api_update_local_stats(timestamp); server->api_update_local_stats(timestamp);
share->m_result = SubmittedShare::Result::OK; share->m_result = SubmittedShare::Result::OK;
@@ -721,16 +867,11 @@ void StratumServer::on_share_found(uv_work_t* req)
void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/) void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
{ {
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data); SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
if (share->m_highEnoughDifficulty) {
bkg_jobs_tracker.stop("StratumServer::on_share_found");
}
ON_SCOPE_LEAVE( ON_SCOPE_LEAVE([share]() { share->m_server->m_submittedSharesPool.push_back(share); });
[share]()
{
{
MutexLock lock(share->m_server->m_submittedSharesPoolLock);
share->m_server->m_submittedSharesPool.push_back(share);
}
bkg_jobs_tracker.stop("StratumServer::on_share_found");
});
StratumClient* client = share->m_client; StratumClient* client = share->m_client;
StratumServer* server = share->m_server; StratumServer* server = share->m_server;
@@ -739,9 +880,9 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) { if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) {
const bool result = server->send(client, const bool result = server->send(client,
[share](void* buf) [share](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
switch (share->m_result) { switch (share->m_result) {
case SubmittedShare::Result::STALE: case SubmittedShare::Result::STALE:
s << "{\"id\":" << share->m_id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n"; s << "{\"id\":" << share->m_id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n";
@@ -777,28 +918,34 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
StratumServer::StratumClient::StratumClient() StratumServer::StratumClient::StratumClient()
: m_rpcId(0) : m_rpcId(0)
, m_perConnectionJobId(0)
, m_connectedTime(0) , m_connectedTime(0)
, m_jobs{} , m_jobs{}
, m_perConnectionJobId(0) , m_autoDiffData{}
, m_autoDiffWindowHashes(0)
, m_autoDiffIndex(0)
, m_customDiff{} , m_customDiff{}
, m_autoDiff{}
, m_customUser{}
{ {
uv_mutex_init_checked(&m_jobsLock);
}
StratumServer::StratumClient::~StratumClient()
{
uv_mutex_destroy(&m_jobsLock);
} }
void StratumServer::StratumClient::reset() void StratumServer::StratumClient::reset()
{ {
Client::reset(); Client::reset();
m_rpcId = 0; m_rpcId = 0;
m_connectedTime = 0;
memset(m_jobs, 0, sizeof(m_jobs));
m_perConnectionJobId = 0; m_perConnectionJobId = 0;
m_connectedTime = 0;
for (int i = 0; i < JOBS_SIZE; ++i) {
m_jobs[i].job_id = 0;
}
m_autoDiffWindowHashes = 0;
m_autoDiffIndex = 0;
m_customDiff = {}; m_customDiff = {};
m_customUser.clear(); m_autoDiff = {};
m_customUser[0] = '\0';
} }
bool StratumServer::StratumClient::on_connect() bool StratumServer::StratumClient::on_connect()
+23 -9
View File
@@ -39,7 +39,7 @@ public:
struct StratumClient : public Client struct StratumClient : public Client
{ {
StratumClient(); StratumClient();
~StratumClient(); FORCEINLINE ~StratumClient() {}
static Client* allocate() { return new StratumClient(); } static Client* allocate() { return new StratumClient(); }
@@ -52,20 +52,32 @@ public:
bool process_submit(rapidjson::Document& doc, uint32_t id); bool process_submit(rapidjson::Document& doc, uint32_t id);
uint32_t m_rpcId; uint32_t m_rpcId;
uint32_t m_perConnectionJobId;
uint64_t m_connectedTime; uint64_t m_connectedTime;
uv_mutex_t m_jobsLock; enum {
JOBS_SIZE = 4,
AUTO_DIFF_SIZE = 64,
};
struct SavedJob { struct SavedJob {
uint32_t job_id; uint32_t job_id;
uint32_t extra_nonce; uint32_t extra_nonce;
uint32_t template_id; uint32_t template_id;
uint64_t target; uint64_t target;
} m_jobs[4]; } m_jobs[JOBS_SIZE];
struct AutoDiffData {
uint16_t m_timestamp;
uint16_t m_hashes;
} m_autoDiffData[AUTO_DIFF_SIZE];
uint64_t m_autoDiffWindowHashes;
uint32_t m_autoDiffIndex;
uint32_t m_perConnectionJobId;
difficulty_type m_customDiff; difficulty_type m_customDiff;
std::string m_customUser; difficulty_type m_autoDiff;
char m_customUser[32];
}; };
bool on_login(StratumClient* client, uint32_t id, const char* login); bool on_login(StratumClient* client, uint32_t id, const char* login);
@@ -73,19 +85,19 @@ public:
uint64_t get_random64(); uint64_t get_random64();
void print_status() override; void print_status() override;
void show_workers();
void reset_share_counters(); void reset_share_counters();
private: private:
void print_stratum_status() const; void print_stratum_status() const;
void update_auto_diff(StratumClient* client, const uint64_t timestamp, const uint64_t hashes);
static bool get_custom_diff(const char* s, difficulty_type& diff);
static bool get_custom_user(const char* s, std::string& user);
static void on_share_found(uv_work_t* req); static void on_share_found(uv_work_t* req);
static void on_after_share_found(uv_work_t* req, int status); static void on_after_share_found(uv_work_t* req, int status);
p2pool* m_pool; p2pool* m_pool;
bool m_autoDiff;
struct BlobsData struct BlobsData
{ {
@@ -125,6 +137,9 @@ private:
uint64_t m_target; uint64_t m_target;
hash m_resultHash; hash m_resultHash;
difficulty_type m_sidechainDifficulty; difficulty_type m_sidechainDifficulty;
uint64_t m_timestamp;
uint64_t m_hashes;
bool m_highEnoughDifficulty;
enum class Result { enum class Result {
STALE, STALE,
@@ -135,7 +150,6 @@ private:
} m_result; } m_result;
}; };
uv_mutex_t m_submittedSharesPoolLock;
std::vector<SubmittedShare*> m_submittedSharesPool; std::vector<SubmittedShare*> m_submittedSharesPool;
struct HashrateData struct HashrateData
+10 -10
View File
@@ -70,6 +70,8 @@ public:
void init_addr_string(bool is_v6, const sockaddr_storage* peer_addr); void init_addr_string(bool is_v6, const sockaddr_storage* peer_addr);
alignas(8) char m_readBuf[READ_BUF_SIZE];
TCPServer* m_owner; TCPServer* m_owner;
// Used to maintain connected clients list // Used to maintain connected clients list
@@ -77,19 +79,17 @@ public:
Client* m_next; Client* m_next;
uv_tcp_t m_socket; uv_tcp_t m_socket;
uv_connect_t m_connectRequest;
bool m_isV6; bool m_isV6;
bool m_isIncoming; bool m_isIncoming;
bool m_readBufInUse;
uint32_t m_numRead;
raw_ip m_addr; raw_ip m_addr;
int m_port; int m_port;
char m_addrString[64]; char m_addrString[64];
bool m_readBufInUse; std::atomic<uint32_t> m_resetCounter;
char m_readBuf[READ_BUF_SIZE];
uint32_t m_numRead;
std::atomic<uint32_t> m_resetCounter{ 0 };
}; };
struct WriteBuf struct WriteBuf
@@ -105,14 +105,14 @@ public:
struct SendCallbackBase struct SendCallbackBase
{ {
virtual ~SendCallbackBase() {} virtual ~SendCallbackBase() {}
virtual size_t operator()(void*) = 0; virtual size_t operator()(void*, size_t) = 0;
}; };
template<typename T> template<typename T>
struct SendCallback : public SendCallbackBase struct SendCallback : public SendCallbackBase
{ {
explicit FORCEINLINE SendCallback(T&& callback) : m_callback(std::move(callback)) {} explicit FORCEINLINE SendCallback(T&& callback) : m_callback(std::move(callback)) {}
size_t operator()(void* buf) override { return m_callback(buf); } size_t operator()(void* buf, size_t buf_size) override { return m_callback(buf, buf_size); }
private: private:
SendCallback& operator=(SendCallback&&) = delete; SendCallback& operator=(SendCallback&&) = delete;
@@ -155,8 +155,8 @@ protected:
uv_mutex_t m_clientsListLock; uv_mutex_t m_clientsListLock;
std::vector<Client*> m_preallocatedClients; std::vector<Client*> m_preallocatedClients;
Client* m_connectedClientsList; Client* m_connectedClientsList;
uint32_t m_numConnections; std::atomic<uint32_t> m_numConnections;
uint32_t m_numIncomingConnections; std::atomic<uint32_t> m_numIncomingConnections;
uv_mutex_t m_bansLock; uv_mutex_t m_bansLock;
unordered_map<raw_ip, std::chrono::steady_clock::time_point> m_bans; unordered_map<raw_ip, std::chrono::steady_clock::time_point> m_bans;
+43 -13
View File
@@ -28,8 +28,8 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
, m_finished(0) , m_finished(0)
, m_listenPort(-1) , m_listenPort(-1)
, m_loopStopped{false} , m_loopStopped{false}
, m_numConnections(0) , m_numConnections{ 0 }
, m_numIncomingConnections(0) , m_numIncomingConnections{ 0 }
{ {
int err = uv_loop_init(&m_loop); int err = uv_loop_init(&m_loop);
if (err) { if (err) {
@@ -37,10 +37,18 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
panic(); panic();
} }
uv_async_init(&m_loop, &m_dropConnectionsAsync, on_drop_connections); err = uv_async_init(&m_loop, &m_dropConnectionsAsync, on_drop_connections);
if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic();
}
m_dropConnectionsAsync.data = this; m_dropConnectionsAsync.data = this;
uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown); err = uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown);
if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic();
}
m_shutdownAsync.data = this; m_shutdownAsync.data = this;
uv_mutex_init_checked(&m_clientsListLock); uv_mutex_init_checked(&m_clientsListLock);
@@ -64,6 +72,7 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
} }
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
// cppcheck-suppress functionStatic
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::~TCPServer() TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::~TCPServer()
{ {
if (m_finished.load() == 0) { if (m_finished.load() == 0) {
@@ -322,6 +331,10 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connect_failed(bool, const raw
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::is_banned(const raw_ip& ip) bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::is_banned(const raw_ip& ip)
{ {
if (ip.is_localhost()) {
return false;
}
const auto cur_time = std::chrono::steady_clock::now(); const auto cur_time = std::chrono::steady_clock::now();
MutexLock lock(m_bansLock); MutexLock lock(m_bansLock);
@@ -372,8 +385,11 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer_nolock(Client* cl
return false; return false;
} }
client->m_connectRequest.data = client; uv_connect_t* connect_request = reinterpret_cast<uv_connect_t*>(client->m_readBuf);
err = uv_tcp_connect(&client->m_connectRequest, &client->m_socket, addr, on_connect); memset(connect_request, 0, sizeof(uv_connect_t));
connect_request->data = client;
err = uv_tcp_connect(connect_request, &client->m_socket, addr, on_connect);
if (err) { if (err) {
LOGERR(1, "failed to initiate tcp connection, error " << uv_err_name(err)); LOGERR(1, "failed to initiate tcp connection, error " << uv_err_name(err));
m_pendingConnections.erase(client->m_addr); m_pendingConnections.erase(client->m_addr);
@@ -488,13 +504,17 @@ template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_status() void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_status()
{ {
LOGINFO(0, "status" << LOGINFO(0, "status" <<
"\nConnections = " << m_numConnections << " (" << m_numIncomingConnections << " incoming)" "\nConnections = " << m_numConnections.load() << " (" << m_numIncomingConnections.load() << " incoming)"
); );
} }
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::ban(const raw_ip& ip, uint64_t seconds) void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::ban(const raw_ip& ip, uint64_t seconds)
{ {
if (ip.is_localhost()) {
return;
}
const auto ban_time = std::chrono::steady_clock::now() + std::chrono::seconds(seconds); const auto ban_time = std::chrono::steady_clock::now() + std::chrono::seconds(seconds);
MutexLock lock(m_bansLock); MutexLock lock(m_bansLock);
@@ -548,7 +568,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
// callback_buf is used in only 1 thread, so it's safe // callback_buf is used in only 1 thread, so it's safe
static uint8_t callback_buf[WRITE_BUF_SIZE]; static uint8_t callback_buf[WRITE_BUF_SIZE];
const size_t bytes_written = callback(callback_buf); const size_t bytes_written = callback(callback_buf, sizeof(callback_buf));
if (bytes_written > WRITE_BUF_SIZE) { if (bytes_written > WRITE_BUF_SIZE) {
LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes"); LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes");
@@ -808,10 +828,21 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client_nolock(uv_stream_t*
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client() TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client()
: m_owner(nullptr)
, m_prev(nullptr)
, m_next(nullptr)
, m_socket{}
, m_isV6(false)
, m_isIncoming(false)
, m_readBufInUse(false)
, m_numRead(0)
, m_addr{}
, m_port(0)
, m_addrString{}
, m_resetCounter{ 0 }
{ {
Client::reset();
m_readBuf[0] = '\0'; m_readBuf[0] = '\0';
m_readBuf[READ_BUF_SIZE - 1] = '\0';
} }
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
@@ -823,14 +854,13 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::reset()
m_prev = nullptr; m_prev = nullptr;
m_next = nullptr; m_next = nullptr;
memset(&m_socket, 0, sizeof(m_socket)); memset(&m_socket, 0, sizeof(m_socket));
memset(&m_connectRequest, 0, sizeof(m_connectRequest));
m_isV6 = false; m_isV6 = false;
m_isIncoming = false; m_isIncoming = false;
m_readBufInUse = false;
m_numRead = 0;
m_addr = {}; m_addr = {};
m_port = -1; m_port = -1;
m_addrString[0] = '\0'; m_addrString[0] = '\0';
m_readBufInUse = false;
m_numRead = 0;
} }
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE> template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
+41 -2
View File
@@ -32,7 +32,7 @@ namespace p2pool {
#define STR2(X) STR(X) #define STR2(X) STR(X)
#define STR(X) #X #define STR(X) #X
const char* VERSION = "v2.0 (built" const char* VERSION = "v2.1 (built"
#if defined(__clang__) #if defined(__clang__)
" with clang/" __clang_version__ " with clang/" __clang_version__
#elif defined(__GNUC__) #elif defined(__GNUC__)
@@ -349,7 +349,7 @@ bool resolve_host(std::string& host, bool& is_v6)
addrinfo hints{}; addrinfo hints{};
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
addrinfo* r = nullptr; addrinfo* r = nullptr;
const int err = getaddrinfo(host.c_str(), nullptr, &hints, &r); const int err = getaddrinfo(host.c_str(), nullptr, &hints, &r);
@@ -384,4 +384,43 @@ bool resolve_host(std::string& host, bool& is_v6)
RandomDeviceSeed RandomDeviceSeed::instance; RandomDeviceSeed RandomDeviceSeed::instance;
struct BSR8
{
uint8_t data[256];
static constexpr BSR8 init() {
BSR8 result = { 55 };
for (int i = 1; i < 256; ++i) {
int x = i;
result.data[i] = 63;
while (x < 0x80) {
--result.data[i];
x <<= 1;
}
}
return result;
}
};
static constexpr BSR8 bsr8_table = BSR8::init();
NOINLINE uint64_t bsr_reference(uint64_t x)
{
uint32_t y = static_cast<uint32_t>(x);
uint64_t n0 = (x == y) ? 0 : 32;
y = static_cast<uint32_t>(x >> n0);
n0 ^= 32;
const uint64_t n1 = (y & 0xFFFF0000UL) ? 0 : 16;
y <<= n1;
const uint64_t n2 = (y & 0xFF000000UL) ? 0 : 8;
y <<= n2;
return bsr8_table.data[y >> 24] - n0 - n1 - n2;
}
} // namespace p2pool } // namespace p2pool
+16
View File
@@ -203,6 +203,22 @@ FORCEINLINE uint64_t seconds_since_epoch()
return duration_cast<seconds>(steady_clock::now().time_since_epoch()).count(); return duration_cast<seconds>(steady_clock::now().time_since_epoch()).count();
} }
uint64_t bsr_reference(uint64_t x);
#ifdef HAVE_BUILTIN_CLZLL
#define bsr(x) (63 - __builtin_clzll(x))
#elif defined HAVE_BITSCANREVERSE64
#pragma intrinsic(_BitScanReverse64)
FORCEINLINE uint64_t bsr(uint64_t x)
{
unsigned long index;
_BitScanReverse64(&index, x);
return index;
}
#else
#define bsr bsr_reference
#endif
} // namespace p2pool } // namespace p2pool
namespace robin_hood { namespace robin_hood {
+1 -2
View File
@@ -89,7 +89,6 @@ Wallet::Wallet(const Wallet& w)
operator=(w); operator=(w);
} }
// cppcheck-suppress operatorEqVarError
Wallet& Wallet::operator=(const Wallet& w) Wallet& Wallet::operator=(const Wallet& w)
{ {
if (this == &w) { if (this == &w) {
@@ -119,7 +118,7 @@ bool Wallet::decode(const char* address)
static_assert(last_block_size_index >= 0, "Check ADDRESS_LENGTH"); static_assert(last_block_size_index >= 0, "Check ADDRESS_LENGTH");
uint8_t data[static_cast<size_t>(num_full_blocks) * sizeof(uint64_t) + last_block_size_index]; uint8_t data[static_cast<size_t>(num_full_blocks) * sizeof(uint64_t) + last_block_size_index] = {};
int data_index = 0; int data_index = 0;
for (int i = 0; i <= num_full_blocks; ++i) { for (int i = 0; i <= num_full_blocks; ++i) {
+7 -9
View File
@@ -49,13 +49,13 @@ ZMQReader::ZMQReader(const char* address, uint32_t zmq_port, MinerCallbackHandle
if (!m_publisherPort) { if (!m_publisherPort) {
LOGERR(1, "failed to to bind ZMQ publisher port, aborting"); LOGERR(1, "failed to to bind ZMQ publisher port, aborting");
panic(); throw zmq::error_t(EFSM);
} }
const int err = uv_thread_create(&m_worker, run_wrapper, this); const int err = uv_thread_create(&m_worker, run_wrapper, this);
if (err) { if (err) {
LOGERR(1, "failed to start ZMQ thread, error " << uv_err_name(err)); LOGERR(1, "failed to start ZMQ thread, error " << uv_err_name(err));
panic(); throw zmq::error_t(EFSM);
} }
} }
@@ -71,8 +71,7 @@ ZMQReader::~ZMQReader()
uv_thread_join(&m_worker); uv_thread_join(&m_worker);
} }
catch (const std::exception& e) { catch (const std::exception& e) {
LOGERR(1, "exception " << e.what() << ", aborting"); LOGERR(1, "exception " << e.what());
panic();
} }
} }
@@ -104,7 +103,7 @@ void ZMQReader::run()
zmq_msg_t message; zmq_msg_t message;
int rc = zmq_msg_init(&message); int rc = zmq_msg_init(&message);
if (rc != 0) { if (rc != 0) {
throw zmq::error_t(); throw zmq::error_t(errno);
} }
LOGINFO(1, "worker thread ready"); LOGINFO(1, "worker thread ready");
@@ -112,7 +111,7 @@ void ZMQReader::run()
do { do {
rc = zmq_msg_recv(&message, m_subscriber, 0); rc = zmq_msg_recv(&message, m_subscriber, 0);
if (rc < 0) { if (rc < 0) {
throw zmq::error_t(); throw zmq::error_t(errno);
} }
if (m_finished.load()) { if (m_finished.load()) {
@@ -125,8 +124,7 @@ void ZMQReader::run()
zmq_msg_close(&message); zmq_msg_close(&message);
} }
catch (const std::exception& e) { catch (const std::exception& e) {
LOGERR(1, "exception " << e.what() << ", aborting"); LOGERR(1, "exception " << e.what());
panic();
} }
} }
@@ -196,7 +194,7 @@ void ZMQReader::parse(char* data, size_t size)
using namespace rapidjson; using namespace rapidjson;
Document doc; Document doc;
if (doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(value, end - value).HasParseError()) { if (doc.Parse<kParseCommentsFlag | kParseTrailingCommasFlag>(value, end - value).HasParseError()) {
LOGWARN(1, "ZeroMQ message failed to parse, skipping it"); LOGWARN(1, "ZeroMQ message failed to parse, skipping it");
return; return;
} }
+16 -49
View File
@@ -3,12 +3,7 @@ project(p2pool_tests)
option(STATIC_LIBS "Use locally built libuv and libzmq static libs" OFF) option(STATIC_LIBS "Use locally built libuv and libzmq static libs" OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0") if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0")
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT p2pool_tests) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT p2pool_tests)
@@ -21,48 +16,7 @@ add_subdirectory(../external/src/RandomX RandomX)
set(LIBS ${LIBS} randomx) set(LIBS ${LIBS} randomx)
add_definitions(-DWITH_RANDOMX) add_definitions(-DWITH_RANDOMX)
if (CMAKE_CXX_COMPILER_ID MATCHES GNU) include(cmake/flags.cmake)
set(WARNING_FLAGS "")
set(OPTIMIZATION_FLAGS "-Ofast -s")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
if (STATIC_LINUX_BINARY)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
set(WARNING_FLAGS "")
set(SECURITY_FLAGS "/GS /guard:cf")
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
set(CMAKE_C_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_C_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_CXX_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(WARNING_FLAGS "")
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
endif()
set(HEADERS set(HEADERS
) )
@@ -74,7 +28,7 @@ set(SOURCES
src/keccak_tests.cpp src/keccak_tests.cpp
src/main.cpp src/main.cpp
src/pool_block_tests.cpp src/pool_block_tests.cpp
src/varint_tests.cpp src/util_tests.cpp
src/wallet_tests.cpp src/wallet_tests.cpp
../external/src/cryptonote/crypto-ops-data.c ../external/src/cryptonote/crypto-ops-data.c
../external/src/cryptonote/crypto-ops.c ../external/src/cryptonote/crypto-ops.c
@@ -160,6 +114,19 @@ endif()
add_definitions(/DZMQ_STATIC /DP2POOL_LOG_DISABLE) add_definitions(/DZMQ_STATIC /DP2POOL_LOG_DISABLE)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("int main(){ return __builtin_clzll(1);}" HAVE_BUILTIN_CLZLL)
check_cxx_source_compiles("#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\nint main(){unsigned long r;_BitScanReverse64(&r,1);return r;}" HAVE_BITSCANREVERSE64)
if (HAVE_BUILTIN_CLZLL)
add_definitions(/DHAVE_BUILTIN_CLZLL)
endif()
if (HAVE_BITSCANREVERSE64)
add_definitions(/DHAVE_BITSCANREVERSE64)
endif()
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES}) add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES})
target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} ${LIBS}) target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} ${LIBS})
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/crypto_tests.txt" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>) add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/crypto_tests.txt" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
+53
View File
@@ -0,0 +1,53 @@
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(GENERAL_FLAGS "-pthread")
set(WARNING_FLAGS "-Wall -Wextra")
set(OPTIMIZATION_FLAGS "-Ofast -s")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
if (WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
if (STATIC_BINARY)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
set(GENERAL_FLAGS "")
set(WARNING_FLAGS "/Wall /sdl")
set(SECURITY_FLAGS "/GS /guard:cf")
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
set(CMAKE_C_FLAGS_DEBUG "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
set(CMAKE_C_FLAGS_RELEASE "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_CXX_FLAGS_RELEASE "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(GENERAL_FLAGS "-pthread")
set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal")
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
endif()
+1 -1
View File
@@ -55,7 +55,7 @@ TEST(hash, empty)
hash h; hash h;
ASSERT_EQ(h.empty(), true); ASSERT_EQ(h.empty(), true);
for (int i = 0; i < HASH_SIZE; ++i) { for (size_t i = 0; i < HASH_SIZE; ++i) {
hash h2; hash h2;
h2.h[i] = 1; h2.h[i] = 1;
ASSERT_EQ(h2.empty(), false); ASSERT_EQ(h2.empty(), false);
@@ -21,7 +21,7 @@
namespace p2pool { namespace p2pool {
TEST(varint, read_write) TEST(util, varint)
{ {
std::vector<uint8_t> v; std::vector<uint8_t> v;
v.reserve(16); v.reserve(16);
@@ -82,4 +82,12 @@ TEST(varint, read_write)
ASSERT_EQ(readVarint(buf2, buf2 + 1, check), nullptr); ASSERT_EQ(readVarint(buf2, buf2 + 1, check), nullptr);
} }
TEST(util, bsr)
{
for (uint64_t i = 0, x = 1; i <= 63; ++i, x <<= 1) {
ASSERT_EQ(bsr(x), i);
ASSERT_EQ(bsr_reference(x), i);
}
}
} }