Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a5be0a321 | |||
| c203f6eb0a | |||
| b713f4e702 | |||
| 111087d96a | |||
| 9e7666d12f | |||
| cb147773b5 | |||
| d84bef8f14 | |||
| 32bb318af4 | |||
| 055b5e2256 | |||
| c1754d122f | |||
| 6d121122f8 | |||
| bfa8334aeb | |||
| 0e222afd6a | |||
| b191962d32 | |||
| 1cf13e142a | |||
| 8f1f81749d | |||
| 72d70eba16 | |||
| ae3612f595 | |||
| 37b6457054 | |||
| 9579be5c7d | |||
| d05d47fa75 | |||
| bd88c04e9e | |||
| eb3a3872eb | |||
| 5cea7be405 | |||
| 516c382fe4 | |||
| 710e55422a | |||
| 3406cf78b4 | |||
| 8fa354796c | |||
| 6c6ef1c1b8 | |||
| c3c326c680 | |||
| 92e20485b2 | |||
| edd782ac23 | |||
| a4d84e318d | |||
| 08ee599f79 | |||
| 134f2d68a3 | |||
| d23c46ff84 | |||
| 820c5db5e8 | |||
| 990916ab62 | |||
| d4e362cd76 | |||
| 1dd06cc509 | |||
| 2e2bd1d137 | |||
| 0818d91f4f | |||
| 6e1f34b168 | |||
| 1a35177633 | |||
| c45689b02b | |||
| 8f27d940e3 | |||
| 6b4640c413 |
@@ -53,6 +53,50 @@ jobs:
|
||||
name: p2pool-${{ matrix.config.os }}
|
||||
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:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -12,14 +12,22 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install cppcheck
|
||||
run: sudo apt update && sudo apt install cppcheck
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
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
|
||||
run: |
|
||||
cd cppcheck
|
||||
@@ -30,14 +38,22 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Install cppcheck
|
||||
run: choco install cppcheck
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
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
|
||||
uses: lukka/get-cmake@latest
|
||||
|
||||
|
||||
+26
-3
@@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 2.8.12)
|
||||
project(p2pool)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
@@ -100,7 +101,7 @@ if (WIN32)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
|
||||
set(LIBS ${LIBS} pthread)
|
||||
elseif (NOT APPLE)
|
||||
set(LIBS ${LIBS} pthread gss dl)
|
||||
set(LIBS ${LIBS} pthread dl)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
@@ -133,9 +134,31 @@ endif()
|
||||
|
||||
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})
|
||||
|
||||
if (STATIC_BINARY)
|
||||
if (STATIC_BINARY OR STATIC_LIBS)
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} ${CMAKE_PROJECT_NAME})
|
||||
|
||||
if (WITH_RANDOMX)
|
||||
|
||||
@@ -271,6 +271,18 @@ cmake ..
|
||||
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
|
||||
|
||||
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
@@ -6,14 +6,15 @@ 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 -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${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} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${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")
|
||||
@@ -25,26 +26,28 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
endif()
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(GENERAL_FLAGS "")
|
||||
set(WARNING_FLAGS "/Wall /WX /sdl")
|
||||
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_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 "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
|
||||
set(CMAKE_CXX_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 "${GENERAL_FLAGS} ${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")
|
||||
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 -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${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} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${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,9 +1,9 @@
|
||||
../src/
|
||||
../external/src/
|
||||
../external/src/cryptonote/
|
||||
../external/src/libuv/
|
||||
../external/src/libuv/include/
|
||||
../external/src/cppzmq/
|
||||
../external/src/libzmq/
|
||||
../external/src/libzmq/include/
|
||||
../external/src/llhttp/
|
||||
../external/src/RandomX/src/
|
||||
../external/src/rapidjson/include
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@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
|
||||
for /f %%i in ("errors_filtered.txt") do set size=%%~zi
|
||||
if %size% gtr 0 (
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
grep -v 'external' errors_full.txt | grep -v 'unmatchedSuppression' > errors_filtered.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 > errors_filtered.txt
|
||||
if [ -s errors_filtered.txt ]; then
|
||||
cat errors_filtered.txt
|
||||
exit 1
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
missingIncludeSystem
|
||||
unusedFunction
|
||||
useStlAlgorithm
|
||||
functionStatic
|
||||
functionConst
|
||||
unmatchedSuppression
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+1
-1
Submodule external/src/RandomX updated: 1adc7d8efd...6e059124bd
Vendored
+1
-1
Submodule external/src/cppzmq updated: a98fa4a91d...26362337a9
Vendored
+1
-1
Submodule external/src/libuv updated: 03a698b9c6...99ab53e998
Vendored
+1
-1
Submodule external/src/libzmq updated: 572eb008f1...37224c93de
Vendored
+1
-1
Submodule external/src/rapidjson updated: 3c8d1dc5a5...6e3ab6dd56
@@ -115,7 +115,7 @@ BlockTemplate& BlockTemplate::operator=(const BlockTemplate& b)
|
||||
m_extraNonceOffsetInTemplate = b.m_extraNonceOffsetInTemplate;
|
||||
m_numTransactionHashes = b.m_numTransactionHashes;
|
||||
m_prevId = b.m_prevId;
|
||||
m_height = b.m_height;
|
||||
m_height = b.m_height.load();
|
||||
m_difficulty = b.m_difficulty;
|
||||
m_seedHash = b.m_seedHash;
|
||||
m_timestamp = b.m_timestamp;
|
||||
@@ -575,7 +575,6 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
|
||||
m_rewards.clear();
|
||||
m_mempoolTxs.clear();
|
||||
m_mempoolTxsOrder.clear();
|
||||
m_shares.clear();
|
||||
}
|
||||
|
||||
#if TEST_MEMPOOL_PICKING_ALGORITHM
|
||||
|
||||
@@ -50,12 +50,11 @@ public:
|
||||
void update_tx_keys();
|
||||
|
||||
FORCEINLINE uint64_t height() const { return m_height; }
|
||||
FORCEINLINE uint64_t timestamp() const { return m_timestamp; }
|
||||
FORCEINLINE difficulty_type difficulty() const { return m_difficulty; }
|
||||
|
||||
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:
|
||||
p2pool* m_pool;
|
||||
@@ -83,7 +82,7 @@ private:
|
||||
|
||||
size_t m_numTransactionHashes;
|
||||
hash m_prevId;
|
||||
uint64_t m_height;
|
||||
std::atomic<uint64_t> m_height;
|
||||
difficulty_type m_difficulty;
|
||||
hash m_seedHash;
|
||||
|
||||
|
||||
+17
-1
@@ -19,22 +19,25 @@
|
||||
|
||||
#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 NOINLINE __declspec(noinline)
|
||||
#define LIKELY(expression) expression
|
||||
#define MSVC_PRAGMA(...) __pragma(__VA_ARGS__)
|
||||
|
||||
#elif __GNUC__
|
||||
|
||||
#define FORCEINLINE __attribute__((always_inline)) inline
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#define LIKELY(expression) __builtin_expect(expression, 1)
|
||||
#define MSVC_PRAGMA(...)
|
||||
|
||||
#else
|
||||
|
||||
#define FORCEINLINE inline
|
||||
#define NOINLINE
|
||||
#define LIKELY(expression) expression
|
||||
#define MSVC_PRAGMA(...)
|
||||
|
||||
#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==(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::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 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
|
||||
// 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()
|
||||
@@ -309,6 +317,14 @@ struct raw_ip
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include "side_chain.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef HAVE_PTHREAD_CANCEL
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static constexpr char log_category_prefix[] = "ConsoleCommands ";
|
||||
|
||||
namespace p2pool {
|
||||
@@ -45,7 +49,7 @@ ConsoleCommands::~ConsoleCommands()
|
||||
|
||||
#ifdef _WIN32
|
||||
TerminateThread(reinterpret_cast<HANDLE>(m_worker->native_handle()), 0);
|
||||
#else
|
||||
#elif defined HAVE_PTHREAD_CANCEL
|
||||
pthread_cancel(m_worker->native_handle());
|
||||
#endif
|
||||
|
||||
@@ -72,7 +76,7 @@ typedef struct cmd {
|
||||
cmdfunc *func;
|
||||
} 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
|
||||
static cmdfunc do_start_mining, do_stop_mining;
|
||||
@@ -85,6 +89,7 @@ static cmd cmds[] = {
|
||||
{ STRCONST("addpeers"), "<peeraddr>", "add peer", do_addpeers },
|
||||
{ STRCONST("droppeers"), "", "disconnect all peers", do_droppeers },
|
||||
{ STRCONST("peers"), "", "show all peers", do_showpeers },
|
||||
{ STRCONST("workers"), "", "show all connected workers", do_showworkers },
|
||||
{ STRCONST("bans"), "", "show all banned IPs", do_showbans },
|
||||
{ STRCONST("outpeers"), "", "set maximum number of outgoing connections", do_outpeers },
|
||||
{ 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;
|
||||
}
|
||||
|
||||
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 */)
|
||||
{
|
||||
if (m_pool->stratum_server()) {
|
||||
|
||||
@@ -238,6 +238,7 @@ private:
|
||||
struct DerivationEntry
|
||||
{
|
||||
hash derivation;
|
||||
// cppcheck-suppress unusedStructMember
|
||||
uint8_t view_tag;
|
||||
};
|
||||
|
||||
|
||||
@@ -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.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";
|
||||
|
||||
m_request.resize(s.m_pos);
|
||||
|
||||
@@ -71,6 +71,7 @@ private:
|
||||
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);
|
||||
void on_read(const char* data, size_t size);
|
||||
// cppcheck-suppress functionConst
|
||||
void close();
|
||||
static void on_close(uv_handle_t* handle);
|
||||
|
||||
|
||||
+24
-57
@@ -48,7 +48,7 @@ NOINLINE void keccakf(uint64_t* st)
|
||||
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
|
||||
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); \
|
||||
st[i + 0 ] ^= t; \
|
||||
st[i + 5] ^= t; \
|
||||
@@ -57,9 +57,11 @@ NOINLINE void keccakf(uint64_t* st)
|
||||
st[i + 20] ^= t; \
|
||||
}
|
||||
|
||||
X(0); X(1); X(2); X(3); X(4);
|
||||
|
||||
#undef X
|
||||
THETA(0);
|
||||
THETA(1);
|
||||
THETA(2);
|
||||
THETA(3);
|
||||
THETA(4);
|
||||
|
||||
// Rho Pi
|
||||
const uint64_t t = st[1];
|
||||
@@ -89,60 +91,25 @@ NOINLINE void keccakf(uint64_t* st)
|
||||
st[10] = ROTL64(t, 1);
|
||||
|
||||
// Chi
|
||||
// unrolled loop, where only last iteration is different
|
||||
int j = 0;
|
||||
bc[0] = st[j + 0];
|
||||
bc[1] = st[j + 1];
|
||||
#define CHI(j) { \
|
||||
const uint64_t st0 = st[j ]; \
|
||||
const uint64_t st1 = 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];
|
||||
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];
|
||||
CHI( 0);
|
||||
CHI( 5);
|
||||
CHI(10);
|
||||
CHI(15);
|
||||
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
|
||||
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;
|
||||
|
||||
for (int i = 0; i < rsizw; i++) {
|
||||
st[i] ^= ((uint64_t*)temp)[i];
|
||||
st[i] ^= reinterpret_cast<uint64_t*>(temp)[i];
|
||||
}
|
||||
|
||||
keccakf(st);
|
||||
|
||||
+7
-10
@@ -194,15 +194,6 @@ private:
|
||||
fwrite(p, 1, size, (severity == 1) ? stdout : stderr);
|
||||
#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 (c) {
|
||||
strip_colors(p, size);
|
||||
@@ -232,6 +223,13 @@ private:
|
||||
// Flush the log file only after all pending log lines have been written
|
||||
if (m_logFile.is_open()) {
|
||||
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);
|
||||
}
|
||||
@@ -278,7 +276,6 @@ static Worker worker;
|
||||
|
||||
#endif // P2POOL_LOG_DISABLE
|
||||
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
|
||||
{
|
||||
m_buf[0] = static_cast<char>(severity);
|
||||
|
||||
@@ -35,8 +35,10 @@ struct Stream
|
||||
{
|
||||
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) {}
|
||||
FORCEINLINE Stream(char* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(static_cast<int>(size) - 1) {}
|
||||
template<size_t N>
|
||||
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>
|
||||
struct Entry
|
||||
@@ -182,7 +184,10 @@ INT_ENTRY(unsigned long)
|
||||
template<typename T, int base>
|
||||
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;
|
||||
};
|
||||
@@ -190,7 +195,7 @@ struct BasedValue
|
||||
template<typename T, int 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);
|
||||
}
|
||||
@@ -302,6 +307,7 @@ struct Hashrate
|
||||
{
|
||||
FORCEINLINE Hashrate() : m_data(0), m_valid(false) {}
|
||||
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;
|
||||
bool m_valid;
|
||||
@@ -309,7 +315,7 @@ struct 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) {
|
||||
return;
|
||||
@@ -354,7 +360,7 @@ struct 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;
|
||||
|
||||
@@ -372,8 +378,7 @@ template<> struct log::Stream::Entry<XMRAmount>
|
||||
|
||||
template<> struct log::Stream::Entry<NetworkType>
|
||||
{
|
||||
// cppcheck-suppress constParameter
|
||||
static NOINLINE void put(const NetworkType& value, Stream* wrapper)
|
||||
static NOINLINE void put(NetworkType value, Stream* wrapper)
|
||||
{
|
||||
switch (value) {
|
||||
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);
|
||||
|
||||
template<> struct log::Stream::Entry<raw_ip>
|
||||
@@ -402,16 +469,47 @@ namespace {
|
||||
#define CONCAT(a, b) CONCAT2(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
|
||||
|
||||
#define LOGINFO(level, ...)
|
||||
#define LOGWARN(level, ...)
|
||||
#define LOGERR(level, ...)
|
||||
#define LOGINFO(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
#define LOGWARN(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
#define LOGERR(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(level, severity, ...) \
|
||||
do { \
|
||||
SIDE_EFFECT_CHECK(level, __VA_ARGS__); \
|
||||
if (level <= log::GLOBAL_LOG_LEVEL) { \
|
||||
log::Writer CONCAT(log_wrapper_, __LINE__)(severity); \
|
||||
CONCAT(log_wrapper_, __LINE__) << log::Gray() << log_category_prefix; \
|
||||
|
||||
+8
-2
@@ -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"
|
||||
"--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"
|
||||
"--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"
|
||||
"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",
|
||||
@@ -84,10 +85,15 @@ int main(int argc, char* argv[])
|
||||
memory_tracking_start();
|
||||
|
||||
p2pool::init_crypto_cache();
|
||||
{
|
||||
|
||||
try {
|
||||
p2pool::p2pool pool(argc, argv);
|
||||
result = pool.run();
|
||||
}
|
||||
catch (...) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
p2pool::destroy_crypto_cache();
|
||||
|
||||
memory_tracking_stop();
|
||||
|
||||
@@ -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); }
|
||||
|
||||
#else
|
||||
// cppcheck-suppress functionStatic
|
||||
void memory_tracking_start() {}
|
||||
// cppcheck-suppress functionStatic
|
||||
void memory_tracking_stop() {}
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
+5
-1
@@ -24,6 +24,7 @@
|
||||
#include "randomx.h"
|
||||
#include "params.h"
|
||||
#include "p2pool_api.h"
|
||||
#include "side_chain.h"
|
||||
#include <thread>
|
||||
|
||||
static constexpr char log_category_prefix[] = "Miner ";
|
||||
@@ -101,8 +102,10 @@ void Miner::on_block(const BlockTemplate& block)
|
||||
m_totalHashes += hash_count;
|
||||
|
||||
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",
|
||||
[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 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
|
||||
<< ",\"time_running\":" << time_running
|
||||
<< ",\"shares_found\":" << m_sharesFound.load()
|
||||
<< ",\"block_reward_share_percent\":" << block_reward_share_percent
|
||||
<< ",\"threads\":" << m_threads
|
||||
<< "}";
|
||||
});
|
||||
|
||||
+103
-44
@@ -37,6 +37,8 @@ static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
|
||||
static constexpr int DEFAULT_BACKLOG = 16;
|
||||
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
|
||||
|
||||
static constexpr size_t SEND_BUF_MIN_SIZE = 256;
|
||||
|
||||
#include "tcp_server.inl"
|
||||
|
||||
namespace p2pool {
|
||||
@@ -75,7 +77,7 @@ P2PServer::P2PServer(p2pool* pool)
|
||||
int err = uv_async_init(&m_loop, &m_broadcastAsync, on_broadcast);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
return;
|
||||
panic();
|
||||
}
|
||||
m_broadcastAsync.data = this;
|
||||
m_broadcastQueue.reserve(2);
|
||||
@@ -149,6 +151,7 @@ void P2PServer::clear_cached_blocks()
|
||||
|
||||
WriteLock lock(m_cachedBlocksLock);
|
||||
|
||||
// cppcheck-suppress identicalConditionAfterEarlyExit
|
||||
if (!m_cachedBlocks) {
|
||||
return;
|
||||
}
|
||||
@@ -288,6 +291,7 @@ void P2PServer::update_peer_connections()
|
||||
|
||||
if (!has_good_peers && ((m_timerCounter % 30) == 0)) {
|
||||
LOGERR(1, "no connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!!!");
|
||||
load_peer_list();
|
||||
if (m_peerListMonero.empty()) {
|
||||
load_monerod_peer_list();
|
||||
}
|
||||
@@ -310,9 +314,14 @@ void P2PServer::update_peer_list()
|
||||
client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61));
|
||||
|
||||
const bool result = send(client,
|
||||
[](void* buf)
|
||||
[](void* buf, size_t buf_size)
|
||||
{
|
||||
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);
|
||||
return 1;
|
||||
});
|
||||
@@ -406,8 +415,13 @@ void P2PServer::save_peer_list()
|
||||
|
||||
void P2PServer::load_peer_list()
|
||||
{
|
||||
size_t old_size;
|
||||
{
|
||||
MutexLock lock(m_peerListLock);
|
||||
old_size = m_peerList.size();
|
||||
}
|
||||
|
||||
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
|
||||
auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) {
|
||||
@@ -417,7 +431,7 @@ void P2PServer::load_peer_list()
|
||||
addrinfo hints{};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
|
||||
addrinfo* result;
|
||||
const int err = getaddrinfo(nodes[i], nullptr, &hints, &result);
|
||||
@@ -426,7 +440,9 @@ void P2PServer::load_peer_list()
|
||||
const char* addr_str;
|
||||
char addr_str_buf[64];
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1];
|
||||
char buf[128];
|
||||
buf[0] = '\0';
|
||||
|
||||
log::Stream s(buf);
|
||||
|
||||
if (r->ai_family == AF_INET6) {
|
||||
@@ -443,7 +459,7 @@ void P2PServer::load_peer_list()
|
||||
}
|
||||
|
||||
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()) {
|
||||
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",
|
||||
[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;
|
||||
|
||||
Document doc;
|
||||
if (doc.Parse(data, size).HasParseError()) {
|
||||
LOGWARN(4, err_str << "(parse error)");
|
||||
LOGWARN(4, ERR_STR "(parse error)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doc.IsObject()) {
|
||||
LOGWARN(4, err_str << "(not an object)");
|
||||
LOGWARN(4, ERR_STR "(not an object)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!doc.HasMember("white_list")) {
|
||||
LOGWARN(4, err_str << "('white_list' not found)");
|
||||
LOGWARN(4, ERR_STR "('white_list' not found)");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& white_list = doc["white_list"];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#undef ERR_STR
|
||||
|
||||
const int port = m_pool->side_chain().is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT;
|
||||
|
||||
const SizeType n = white_list.Size();
|
||||
@@ -780,7 +798,8 @@ void P2PServer::on_broadcast()
|
||||
}
|
||||
|
||||
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* p = p0;
|
||||
|
||||
@@ -798,9 +817,14 @@ void P2PServer::on_broadcast()
|
||||
|
||||
if (send_pruned) {
|
||||
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());
|
||||
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));
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
@@ -811,9 +835,14 @@ void P2PServer::on_broadcast()
|
||||
}
|
||||
else {
|
||||
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());
|
||||
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));
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
@@ -837,25 +866,12 @@ uint64_t P2PServer::get_random64()
|
||||
|
||||
void P2PServer::print_status()
|
||||
{
|
||||
const int64_t uptime = seconds_since_epoch() - m_pool->start_time();
|
||||
|
||||
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';
|
||||
MutexLock lock(m_peerListLock);
|
||||
|
||||
LOGINFO(0, "status" <<
|
||||
"\nConnections = " << m_numConnections << " (" << m_numIncomingConnections << " incoming)" <<
|
||||
"\nConnections = " << m_numConnections.load() << " (" << m_numIncomingConnections.load() << " incoming)" <<
|
||||
"\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);
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
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) {
|
||||
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()
|
||||
@@ -980,12 +1001,17 @@ void P2PServer::download_missing_blocks()
|
||||
}
|
||||
|
||||
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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
@@ -1012,6 +1038,7 @@ void P2PServer::check_zmq()
|
||||
if (cur_time >= last_active + 300) {
|
||||
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!!!");
|
||||
m_pool->restart_zmq();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,12 +1375,17 @@ bool P2PServer::P2PClient::send_handshake_challenge()
|
||||
m_handshakeChallenge = owner->get_random64();
|
||||
|
||||
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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending HANDSHAKE_CHALLENGE");
|
||||
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE);
|
||||
|
||||
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,
|
||||
[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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending HANDSHAKE_SOLUTION");
|
||||
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION);
|
||||
|
||||
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,
|
||||
[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* p = p0;
|
||||
on_after_handshake(p);
|
||||
@@ -1679,15 +1722,21 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
|
||||
}
|
||||
|
||||
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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending 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));
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
@@ -1841,12 +1890,17 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
}
|
||||
|
||||
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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending PEER_LIST_RESPONSE");
|
||||
*(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE);
|
||||
*(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,
|
||||
[&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* p = p0;
|
||||
|
||||
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
|
||||
+3
-3
@@ -133,7 +133,7 @@ public:
|
||||
|
||||
void print_status() override;
|
||||
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_incoming_peers() const { return m_maxIncomingPeers; }
|
||||
@@ -181,7 +181,7 @@ private:
|
||||
|
||||
uint64_t m_peerId;
|
||||
|
||||
uv_mutex_t m_peerListLock;
|
||||
mutable uv_mutex_t m_peerListLock;
|
||||
|
||||
struct Peer
|
||||
{
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
|
||||
std::vector<Peer> m_peerList;
|
||||
std::vector<Peer> m_peerListMonero;
|
||||
uint64_t m_peerListLastSaved;
|
||||
std::atomic<uint64_t> m_peerListLastSaved;
|
||||
|
||||
struct Broadcast
|
||||
{
|
||||
|
||||
+62
-9
@@ -35,6 +35,7 @@
|
||||
#include "crypto.h"
|
||||
#include "p2pool_api.h"
|
||||
#include "pool_block.h"
|
||||
#include "keccak.h"
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
|
||||
@@ -60,13 +61,13 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
|
||||
if (!m_params->m_wallet.valid()) {
|
||||
LOGERR(1, "Invalid wallet address. Try \"p2pool --help\".");
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
bool is_v6;
|
||||
if (!resolve_host(m_params->m_host, is_v6)) {
|
||||
LOGERR(1, "resolve_host failed for " << m_params->m_host);
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
hash pub, sec, eph_public_key;
|
||||
@@ -75,7 +76,7 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
uint8_t 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");
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
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);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
m_submitBlockAsync.data = this;
|
||||
|
||||
err = uv_async_init(uv_default_loop_checked(), &m_blockTemplateAsync, on_update_block_template);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
m_blockTemplateAsync.data = this;
|
||||
|
||||
err = uv_async_init(uv_default_loop_checked(), &m_stopAsync, on_stop);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
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_minerDataLock);
|
||||
uv_mutex_init_checked(&m_foundBlocksLock);
|
||||
@@ -120,7 +128,7 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
|
||||
if (m_params->m_localStats && !m_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);
|
||||
@@ -294,7 +302,8 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
WriteLock lock(m_mainchainLock);
|
||||
|
||||
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");
|
||||
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_blockTemplateAsync), 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());
|
||||
}
|
||||
|
||||
@@ -632,7 +642,14 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
if (parse_block_headers_range(data, size) == current_height - start_height) {
|
||||
update_median_timestamp();
|
||||
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_p2pServer = new P2PServer(this);
|
||||
#ifdef WITH_RANDOMX
|
||||
@@ -895,6 +912,8 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
|
||||
|
||||
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\"}",
|
||||
[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));
|
||||
get_miner_data();
|
||||
}
|
||||
else {
|
||||
m_getMinerDataPending = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size);
|
||||
|
||||
@@ -1376,6 +1406,29 @@ void p2pool::stop()
|
||||
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()
|
||||
{
|
||||
if (!m_params->ok()) {
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
|
||||
uint64_t zmq_last_active() const { return m_zmqLastActive; }
|
||||
uint64_t start_time() const { return m_startTime; }
|
||||
void restart_zmq();
|
||||
|
||||
private:
|
||||
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_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_restart_zmq(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->restart_zmq(); }
|
||||
|
||||
void submit_block() const;
|
||||
|
||||
@@ -197,8 +199,12 @@ private:
|
||||
|
||||
std::atomic<uint64_t> m_zmqLastActive;
|
||||
uint64_t m_startTime;
|
||||
uv_async_t m_restartZMQAsync;
|
||||
|
||||
ZMQReader* m_ZMQReader = nullptr;
|
||||
|
||||
hash m_getMinerDataHash;
|
||||
bool m_getMinerDataPending = false;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
@@ -131,12 +131,10 @@ void p2pool_api::dump_to_file()
|
||||
{
|
||||
MutexLock lock(m_dumpDataLock);
|
||||
data = std::move(m_dumpData);
|
||||
// cppcheck-suppress accessMoved
|
||||
m_dumpData.clear();
|
||||
}
|
||||
|
||||
for (auto& it : data) {
|
||||
// cppcheck-suppress uninitvar
|
||||
DumpFileWork* work = new DumpFileWork{ {}, {}, {}, it.first, std::move(it.second) };
|
||||
work->open_req.data = work;
|
||||
work->write_req.data = work;
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
LOCAL,
|
||||
};
|
||||
|
||||
// cppcheck-suppress functionConst
|
||||
void on_stop();
|
||||
|
||||
template<typename T>
|
||||
|
||||
+6
-1
@@ -125,10 +125,15 @@ Params::Params(int argc, char* argv[])
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "--no-autodiff") == 0) {
|
||||
m_autoDiff = false;
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]);
|
||||
p2pool_usage();
|
||||
panic();
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ struct Params
|
||||
uint32_t m_maxIncomingPeers = 1000;
|
||||
uint32_t m_minerThreads = 0;
|
||||
bool m_mini = false;
|
||||
bool m_autoDiff = true;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
@@ -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);
|
||||
READ_BUF(m_sidechainId.h, HASH_SIZE);
|
||||
|
||||
// cppcheck-suppress duplicateExpression
|
||||
if (static_cast<uint64_t>(data - tx_extra_begin) != tx_extra_size) return __LINE__;
|
||||
|
||||
EXPECT_BYTE(0);
|
||||
|
||||
@@ -180,7 +180,6 @@ void RandomX_Hasher::set_seed(const hash& seed)
|
||||
}
|
||||
|
||||
{
|
||||
// cppcheck-suppress unreadVariable
|
||||
ON_SCOPE_LEAVE([this]() { uv_rwlock_wrunlock(&m_cacheLock); });
|
||||
|
||||
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
|
||||
if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) {
|
||||
// cppcheck-suppress unreadVariable
|
||||
ON_SCOPE_LEAVE([this]() { uv_rwlock_rdunlock(&m_datasetLock); });
|
||||
|
||||
if (m_stopped.load()) {
|
||||
|
||||
+115
-53
@@ -61,6 +61,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
: m_pool(pool)
|
||||
, m_networkType(type)
|
||||
, m_chainTip{ nullptr }
|
||||
, m_seenWalletsLastPruneTime(0)
|
||||
, m_poolName(pool_name ? pool_name : "default")
|
||||
, m_targetBlockTime(10)
|
||||
, m_minDifficulty(MIN_DIFFICULTY, 0)
|
||||
@@ -78,12 +79,12 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
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_rwlock_init_checked(&m_curDifficultyLock);
|
||||
|
||||
m_difficultyData.reserve(m_chainWindowSize);
|
||||
m_tmpShares.reserve(m_chainWindowSize * 2);
|
||||
m_tmpRewards.reserve(m_chainWindowSize * 2);
|
||||
|
||||
LOGINFO(1, "generating consensus ID");
|
||||
|
||||
@@ -162,16 +163,18 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
|
||||
SideChain::~SideChain()
|
||||
{
|
||||
uv_mutex_destroy(&m_sidechainLock);
|
||||
uv_rwlock_destroy(&m_sidechainLock);
|
||||
uv_mutex_destroy(&m_seenWalletsLock);
|
||||
uv_mutex_destroy(&m_seenBlocksLock);
|
||||
for (auto& it : m_blocksById) {
|
||||
uv_rwlock_destroy(&m_curDifficultyLock);
|
||||
for (const auto& it : m_blocksById) {
|
||||
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_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 (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
|
||||
if (!uncle || !uncle->m_verified || uncle->m_invalid) {
|
||||
continue;
|
||||
@@ -221,16 +228,13 @@ void SideChain::fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txk
|
||||
bool same_chain = false;
|
||||
do {
|
||||
tmp = tip;
|
||||
while (tmp->m_sidechainHeight > uncle->m_sidechainHeight) {
|
||||
while (tmp && (tmp->m_sidechainHeight > uncle->m_sidechainHeight)) {
|
||||
tmp = get_parent(tmp);
|
||||
if (!tmp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!tmp || (tmp->m_sidechainHeight < uncle->m_sidechainHeight)) {
|
||||
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) {
|
||||
if (tmp->m_parent == tmp2->m_parent) {
|
||||
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_difficulty = m_curDifficulty;
|
||||
block.m_difficulty = difficulty();
|
||||
block.m_cumulativeDifficulty = tip->m_cumulativeDifficulty + block.m_difficulty;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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()) {
|
||||
LOGINFO(4, "add_external_block: block " << block.m_sidechainId << " is already added");
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -479,7 +484,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
|
||||
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())) {
|
||||
missing_blocks.push_back(block.m_parent);
|
||||
}
|
||||
@@ -520,8 +525,12 @@ void SideChain::add_block(const 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 });
|
||||
if (!result.second) {
|
||||
@@ -551,13 +560,11 @@ void SideChain::add_block(const PoolBlock& block)
|
||||
else {
|
||||
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);
|
||||
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)
|
||||
{
|
||||
MutexLock lock(m_sidechainLock);
|
||||
WriteLock lock(m_sidechainLock);
|
||||
m_watchBlock = data;
|
||||
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;
|
||||
|
||||
// Empty hash means we return current sidechain tip
|
||||
if (id == hash()) {
|
||||
if (id.empty()) {
|
||||
block = m_chainTip;
|
||||
|
||||
// Don't return stale chain tip
|
||||
if (block && (block->m_txinGenHeight + 2 < m_pool->miner_data().height)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
MutexLock lock(m_sidechainLock);
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
auto it = m_blocksById.find(block->m_sidechainId);
|
||||
if (it != m_blocksById.end()) {
|
||||
@@ -630,11 +642,14 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
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;
|
||||
}
|
||||
|
||||
const size_t n = m_tmpShares.size();
|
||||
const size_t n = tmpShares.size();
|
||||
|
||||
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;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
writeVarint(m_tmpRewards[i], blob);
|
||||
writeVarint(tmpRewards[i], blob);
|
||||
|
||||
blob.emplace_back(tx_type);
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void SideChain::print_status()
|
||||
void SideChain::print_status() const
|
||||
{
|
||||
std::vector<hash> blocks_in_window;
|
||||
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 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;
|
||||
uint64_t network_hashrate = udiv128(network_diff.hi, network_diff.lo, 120, &rem);
|
||||
@@ -736,7 +753,11 @@ void SideChain::print_status()
|
||||
if (tip) {
|
||||
std::sort(blocks_in_window.begin(), blocks_in_window.end());
|
||||
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)) {
|
||||
LOGINFO(4, "orphan block at height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << ": " << log::Gray() << block->m_sidechainId);
|
||||
++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;
|
||||
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
|
||||
{
|
||||
const PoolBlock* tip = m_chainTip;
|
||||
@@ -821,16 +874,19 @@ uint64_t SideChain::miner_count()
|
||||
{
|
||||
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
|
||||
for (auto it = m_seenWallets.begin(); it != m_seenWallets.end();) {
|
||||
if (it->second + 72 * 60 * 60 <= cur_time) {
|
||||
it = m_seenWallets.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
// Every 5 minutes, delete wallets that weren't seen for more than 72 hours
|
||||
if (m_seenWalletsLastPruneTime + 5 * 60 <= cur_time) {
|
||||
for (auto it = m_seenWallets.begin(); it != m_seenWallets.end();) {
|
||||
if (it->second + 72 * 60 * 60 < cur_time) {
|
||||
it = m_seenWallets.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
m_seenWalletsLastPruneTime = cur_time;
|
||||
}
|
||||
|
||||
return m_seenWallets.size();
|
||||
@@ -1405,10 +1461,13 @@ void SideChain::update_chain_tip(PoolBlock* block)
|
||||
difficulty_type diff;
|
||||
if (get_difficulty(block, m_difficultyData, diff)) {
|
||||
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() <<
|
||||
", next difficulty = " << log::Gray() << m_curDifficulty << log::NoColor() <<
|
||||
", next difficulty = " << log::Gray() << diff << log::NoColor() <<
|
||||
", main chain height = " << log::Gray() << block->m_txinGenHeight);
|
||||
|
||||
block->m_wantBroadcast = true;
|
||||
@@ -1419,6 +1478,7 @@ void SideChain::update_chain_tip(PoolBlock* block)
|
||||
StratumServer* s = m_pool->stratum_server();
|
||||
if (s && is_alternative) {
|
||||
s->reset_share_counters();
|
||||
LOGINFO(0, log::LightCyan() << "SYNCHRONIZED");
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
// Switching from an empty to a non-empty chain
|
||||
is_alternative = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If these two blocks are on the same chain, they must have a common ancestor
|
||||
|
||||
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;
|
||||
block_ancestor = get_parent(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();
|
||||
|
||||
MutexLock lock(m_sidechainLock);
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
for (auto& b : m_blocksById) {
|
||||
if (b.second->m_verified) {
|
||||
|
||||
+14
-11
@@ -43,21 +43,22 @@ public:
|
||||
SideChain(p2pool* pool, NetworkType type, const char* pool_name = nullptr);
|
||||
~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);
|
||||
void unsee_block(const PoolBlock& block);
|
||||
bool add_external_block(PoolBlock& block, std::vector<hash>& missing_blocks);
|
||||
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);
|
||||
|
||||
bool get_block_blob(const hash& id, std::vector<uint8_t>& blob);
|
||||
bool get_outputs_blob(PoolBlock* block, uint64_t total_reward, 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) 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
|
||||
// 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; }
|
||||
uint64_t chain_window_size() const { return m_chainWindowSize; }
|
||||
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;
|
||||
uint64_t block_time() const { return m_targetBlockTime; }
|
||||
uint64_t miner_count();
|
||||
@@ -88,7 +89,7 @@ private:
|
||||
void verify_loop(PoolBlock* block);
|
||||
void verify(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"
|
||||
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 check_config();
|
||||
|
||||
mutable uv_mutex_t m_sidechainLock;
|
||||
mutable uv_rwlock_t m_sidechainLock;
|
||||
std::atomic<PoolBlock*> m_chainTip;
|
||||
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
|
||||
unordered_map<hash, PoolBlock*> m_blocksById;
|
||||
|
||||
uv_mutex_t m_seenWalletsLock;
|
||||
unordered_map<hash, uint64_t> m_seenWallets;
|
||||
std::vector<MinerShare> m_tmpShares;
|
||||
std::vector<uint64_t> m_tmpRewards;
|
||||
uint64_t m_seenWalletsLastPruneTime;
|
||||
|
||||
uv_mutex_t m_seenBlocksLock;
|
||||
unordered_set<hash> m_seenBlocks;
|
||||
@@ -121,6 +123,7 @@ private:
|
||||
std::vector<uint8_t> m_consensusId;
|
||||
std::string m_consensusIdDisplayStr;
|
||||
|
||||
mutable uv_rwlock_t m_curDifficultyLock;
|
||||
difficulty_type m_curDifficulty;
|
||||
|
||||
ChainMain m_watchBlock;
|
||||
|
||||
+231
-84
@@ -27,9 +27,11 @@ static constexpr char log_category_prefix[] = "StratumServer ";
|
||||
|
||||
static constexpr int DEFAULT_BACKLOG = 128;
|
||||
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
|
||||
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"
|
||||
|
||||
@@ -38,6 +40,7 @@ namespace p2pool {
|
||||
StratumServer::StratumServer(p2pool* pool)
|
||||
: TCPServer(StratumClient::allocate)
|
||||
, m_pool(pool)
|
||||
, m_autoDiff(pool->params().m_autoDiff)
|
||||
, m_extraNonce(0)
|
||||
, m_rng(RandomDeviceSeed::instance)
|
||||
, m_cumulativeHashes(0)
|
||||
@@ -57,7 +60,6 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
|
||||
uv_mutex_init_checked(&m_blobsQueueLock);
|
||||
uv_mutex_init_checked(&m_rngLock);
|
||||
uv_mutex_init_checked(&m_submittedSharesPoolLock);
|
||||
uv_rwlock_init_checked(&m_hashrateDataLock);
|
||||
|
||||
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);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
return;
|
||||
panic();
|
||||
}
|
||||
m_blobsAsync.data = this;
|
||||
m_blobsQueue.reserve(2);
|
||||
@@ -84,7 +86,6 @@ StratumServer::~StratumServer()
|
||||
|
||||
uv_mutex_destroy(&m_blobsQueueLock);
|
||||
uv_mutex_destroy(&m_rngLock);
|
||||
uv_mutex_destroy(&m_submittedSharesPoolLock);
|
||||
uv_rwlock_destroy(&m_hashrateDataLock);
|
||||
|
||||
for (SubmittedShare* share : m_submittedSharesPool) {
|
||||
@@ -101,6 +102,7 @@ void StratumServer::on_block(const BlockTemplate& block)
|
||||
LOGINFO(4, "no clients connected");
|
||||
return;
|
||||
}
|
||||
m_extraNonce.exchange(num_connections);
|
||||
|
||||
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()
|
||||
// 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;
|
||||
m_extraNonce.exchange(blobs_data->m_numClientsExpected);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
// Integrity checks
|
||||
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
|
||||
while (s && (user.length() < 64)) {
|
||||
while (s && (len < N - 1)) {
|
||||
const char c = *s;
|
||||
if (!c) {
|
||||
break;
|
||||
@@ -192,15 +194,16 @@ bool StratumServer::get_custom_user(const char* s, std::string& user)
|
||||
}
|
||||
// Limit to printable ASCII characters
|
||||
if (c >= ' ' && c <= '~') {
|
||||
user += c;
|
||||
user[len++] = c;
|
||||
}
|
||||
++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;
|
||||
|
||||
@@ -219,8 +222,8 @@ bool StratumServer::get_custom_diff(const char* s, difficulty_type& diff)
|
||||
if (diff_str) {
|
||||
const uint64_t t = strtoull(diff_str + 1, nullptr, 10);
|
||||
if (t) {
|
||||
// Don't let clients set difficulty less than 1000
|
||||
diff = { std::max<uint64_t>(t + 1, 1000), 0 };
|
||||
// Don't let clients set difficulty less than MIN_DIFF
|
||||
diff = { std::max<uint64_t>(t + 1, MIN_DIFF), 0 };
|
||||
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)) {
|
||||
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;
|
||||
{
|
||||
MutexLock lock(client->m_jobsLock);
|
||||
job_id = ++client->m_perConnectionJobId;
|
||||
|
||||
job_id = client->m_perConnectionJobId++;
|
||||
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
saved_job.job_id = job_id;
|
||||
saved_job.extra_nonce = extra_nonce;
|
||||
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,
|
||||
[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 {
|
||||
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);
|
||||
}
|
||||
|
||||
log::Stream s(reinterpret_cast<char*>(buf));
|
||||
log::Stream s(buf, buf_size);
|
||||
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"";
|
||||
s << log::Hex(client->m_rpcId) << "\",\"job\":{\"blob\":\"";
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
{
|
||||
MutexLock lock(client->m_jobsLock);
|
||||
|
||||
const StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
|
||||
const StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
if (saved_job.job_id == job_id) {
|
||||
template_id = saved_job.template_id;
|
||||
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)) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share");
|
||||
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";
|
||||
return s.m_pos;
|
||||
});
|
||||
}
|
||||
|
||||
if (mainchain_diff.check_pow(resultHash)) {
|
||||
const std::string& 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");
|
||||
const char* s = client->m_customUser;
|
||||
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);
|
||||
block.update_tx_keys();
|
||||
}
|
||||
|
||||
SubmittedShare* share;
|
||||
|
||||
{
|
||||
MutexLock lock(m_submittedSharesPoolLock);
|
||||
if (!m_submittedSharesPool.empty()) {
|
||||
share = m_submittedSharesPool.back();
|
||||
m_submittedSharesPool.pop_back();
|
||||
}
|
||||
else {
|
||||
share = new SubmittedShare{};
|
||||
}
|
||||
|
||||
if (!m_submittedSharesPool.empty()) {
|
||||
share = m_submittedSharesPool.back();
|
||||
m_submittedSharesPool.pop_back();
|
||||
}
|
||||
else {
|
||||
share = new SubmittedShare{};
|
||||
}
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target = (target >> 32) << 32;
|
||||
}
|
||||
|
||||
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_resultHash = resultHash;
|
||||
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 (!share->m_sidechainDifficulty.check_pow(share->m_resultHash)) {
|
||||
if (!share->m_highEnoughDifficulty) {
|
||||
on_share_found(&share->m_req);
|
||||
on_after_share_found(&share->m_req, 0);
|
||||
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");
|
||||
|
||||
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";
|
||||
return s.m_pos;
|
||||
});
|
||||
@@ -441,8 +453,53 @@ void StratumServer::print_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()
|
||||
{
|
||||
m_cumulativeHashes = 0;
|
||||
m_cumulativeHashesAtLastShare = 0;
|
||||
m_cumulativeFoundSharesDiff = 0.0;
|
||||
m_totalFoundShares = 0;
|
||||
@@ -495,10 +552,83 @@ void StratumServer::print_stratum_status() const
|
||||
"\nShares found = " << m_totalFoundShares <<
|
||||
"\nAverage effort = " << average_effort << '%' <<
|
||||
"\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()
|
||||
{
|
||||
std::vector<BlobsData*> blobs_queue;
|
||||
@@ -555,14 +685,32 @@ void StratumServer::on_blobs_ready()
|
||||
if (client->m_customDiff.lo) {
|
||||
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;
|
||||
{
|
||||
MutexLock lock3(client->m_jobsLock);
|
||||
job_id = ++client->m_perConnectionJobId;
|
||||
|
||||
job_id = client->m_perConnectionJobId++;
|
||||
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % array_size(&StratumClient::m_jobs)];
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
saved_job.job_id = job_id;
|
||||
saved_job.extra_nonce = extra_nonce;
|
||||
saved_job.template_id = data->m_templateId;
|
||||
@@ -570,7 +718,7 @@ void StratumServer::on_blobs_ready()
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -579,7 +727,7 @@ void StratumServer::on_blobs_ready()
|
||||
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 << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\"";
|
||||
s << log::Hex(job_id) << "\",\"target\":\"";
|
||||
@@ -597,8 +745,9 @@ void StratumServer::on_blobs_ready()
|
||||
}
|
||||
}
|
||||
|
||||
if (numClientsProcessed != m_numConnections) {
|
||||
LOGWARN(1, "client list is broken, expected " << m_numConnections << ", got " << numClientsProcessed << " clients");
|
||||
const uint32_t num_connections = m_numConnections;
|
||||
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)
|
||||
{
|
||||
bkg_jobs_tracker.start("StratumServer::on_share_found");
|
||||
|
||||
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
bkg_jobs_tracker.start("StratumServer::on_share_found");
|
||||
}
|
||||
|
||||
StratumClient* client = share->m_client;
|
||||
StratumServer* server = share->m_server;
|
||||
p2pool* pool = server->m_pool;
|
||||
|
||||
uint64_t target = share->m_target;
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target = (target >> 32) << 32;
|
||||
}
|
||||
|
||||
uint64_t rem;
|
||||
const uint64_t hashes = (target > 1) ? udiv128(1, 0, target, &rem) : 0;
|
||||
const uint64_t target = share->m_target;
|
||||
const uint64_t hashes = share->m_hashes;
|
||||
|
||||
if (pool->stopped()) {
|
||||
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];
|
||||
uint64_t height;
|
||||
difficulty_type difficulty;
|
||||
@@ -698,8 +844,8 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
server->m_cumulativeFoundSharesDiff += diff;
|
||||
++server->m_totalFoundShares;
|
||||
|
||||
const std::string& 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 << '%');
|
||||
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 ? " user " : "") << s << ", effort " << effort << '%');
|
||||
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));
|
||||
|
||||
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->api_update_local_stats(timestamp);
|
||||
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*/)
|
||||
{
|
||||
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
bkg_jobs_tracker.stop("StratumServer::on_share_found");
|
||||
}
|
||||
|
||||
ON_SCOPE_LEAVE(
|
||||
[share]()
|
||||
{
|
||||
{
|
||||
MutexLock lock(share->m_server->m_submittedSharesPoolLock);
|
||||
share->m_server->m_submittedSharesPool.push_back(share);
|
||||
}
|
||||
bkg_jobs_tracker.stop("StratumServer::on_share_found");
|
||||
});
|
||||
ON_SCOPE_LEAVE([share]() { share->m_server->m_submittedSharesPool.push_back(share); });
|
||||
|
||||
StratumClient* client = share->m_client;
|
||||
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)) {
|
||||
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) {
|
||||
case SubmittedShare::Result::STALE:
|
||||
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()
|
||||
: m_rpcId(0)
|
||||
, m_perConnectionJobId(0)
|
||||
, m_connectedTime(0)
|
||||
, m_jobs{}
|
||||
, m_perConnectionJobId(0)
|
||||
, m_autoDiffData{}
|
||||
, m_autoDiffWindowHashes(0)
|
||||
, m_autoDiffIndex(0)
|
||||
, m_customDiff{}
|
||||
, m_autoDiff{}
|
||||
, m_customUser{}
|
||||
{
|
||||
uv_mutex_init_checked(&m_jobsLock);
|
||||
}
|
||||
|
||||
StratumServer::StratumClient::~StratumClient()
|
||||
{
|
||||
uv_mutex_destroy(&m_jobsLock);
|
||||
}
|
||||
|
||||
void StratumServer::StratumClient::reset()
|
||||
{
|
||||
Client::reset();
|
||||
m_rpcId = 0;
|
||||
m_connectedTime = 0;
|
||||
memset(m_jobs, 0, sizeof(m_jobs));
|
||||
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_customUser.clear();
|
||||
m_autoDiff = {};
|
||||
m_customUser[0] = '\0';
|
||||
}
|
||||
|
||||
bool StratumServer::StratumClient::on_connect()
|
||||
|
||||
+23
-9
@@ -39,7 +39,7 @@ public:
|
||||
struct StratumClient : public Client
|
||||
{
|
||||
StratumClient();
|
||||
~StratumClient();
|
||||
FORCEINLINE ~StratumClient() {}
|
||||
|
||||
static Client* allocate() { return new StratumClient(); }
|
||||
|
||||
@@ -52,20 +52,32 @@ public:
|
||||
bool process_submit(rapidjson::Document& doc, uint32_t id);
|
||||
|
||||
uint32_t m_rpcId;
|
||||
uint32_t m_perConnectionJobId;
|
||||
uint64_t m_connectedTime;
|
||||
|
||||
uv_mutex_t m_jobsLock;
|
||||
enum {
|
||||
JOBS_SIZE = 4,
|
||||
AUTO_DIFF_SIZE = 64,
|
||||
};
|
||||
|
||||
struct SavedJob {
|
||||
uint32_t job_id;
|
||||
uint32_t extra_nonce;
|
||||
uint32_t template_id;
|
||||
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;
|
||||
std::string m_customUser;
|
||||
difficulty_type m_autoDiff;
|
||||
char m_customUser[32];
|
||||
};
|
||||
|
||||
bool on_login(StratumClient* client, uint32_t id, const char* login);
|
||||
@@ -73,19 +85,19 @@ public:
|
||||
uint64_t get_random64();
|
||||
|
||||
void print_status() override;
|
||||
void show_workers();
|
||||
|
||||
void reset_share_counters();
|
||||
|
||||
private:
|
||||
void print_stratum_status() const;
|
||||
|
||||
static bool get_custom_diff(const char* s, difficulty_type& diff);
|
||||
static bool get_custom_user(const char* s, std::string& user);
|
||||
void update_auto_diff(StratumClient* client, const uint64_t timestamp, const uint64_t hashes);
|
||||
|
||||
static void on_share_found(uv_work_t* req);
|
||||
static void on_after_share_found(uv_work_t* req, int status);
|
||||
|
||||
p2pool* m_pool;
|
||||
bool m_autoDiff;
|
||||
|
||||
struct BlobsData
|
||||
{
|
||||
@@ -125,6 +137,9 @@ private:
|
||||
uint64_t m_target;
|
||||
hash m_resultHash;
|
||||
difficulty_type m_sidechainDifficulty;
|
||||
uint64_t m_timestamp;
|
||||
uint64_t m_hashes;
|
||||
bool m_highEnoughDifficulty;
|
||||
|
||||
enum class Result {
|
||||
STALE,
|
||||
@@ -135,7 +150,6 @@ private:
|
||||
} m_result;
|
||||
};
|
||||
|
||||
uv_mutex_t m_submittedSharesPoolLock;
|
||||
std::vector<SubmittedShare*> m_submittedSharesPool;
|
||||
|
||||
struct HashrateData
|
||||
|
||||
+10
-10
@@ -70,6 +70,8 @@ public:
|
||||
|
||||
void init_addr_string(bool is_v6, const sockaddr_storage* peer_addr);
|
||||
|
||||
alignas(8) char m_readBuf[READ_BUF_SIZE];
|
||||
|
||||
TCPServer* m_owner;
|
||||
|
||||
// Used to maintain connected clients list
|
||||
@@ -77,19 +79,17 @@ public:
|
||||
Client* m_next;
|
||||
|
||||
uv_tcp_t m_socket;
|
||||
uv_connect_t m_connectRequest;
|
||||
|
||||
bool m_isV6;
|
||||
bool m_isIncoming;
|
||||
bool m_readBufInUse;
|
||||
uint32_t m_numRead;
|
||||
|
||||
raw_ip m_addr;
|
||||
int m_port;
|
||||
char m_addrString[64];
|
||||
|
||||
bool m_readBufInUse;
|
||||
char m_readBuf[READ_BUF_SIZE];
|
||||
uint32_t m_numRead;
|
||||
|
||||
std::atomic<uint32_t> m_resetCounter{ 0 };
|
||||
std::atomic<uint32_t> m_resetCounter;
|
||||
};
|
||||
|
||||
struct WriteBuf
|
||||
@@ -105,14 +105,14 @@ public:
|
||||
struct SendCallbackBase
|
||||
{
|
||||
virtual ~SendCallbackBase() {}
|
||||
virtual size_t operator()(void*) = 0;
|
||||
virtual size_t operator()(void*, size_t) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SendCallback : public SendCallbackBase
|
||||
{
|
||||
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:
|
||||
SendCallback& operator=(SendCallback&&) = delete;
|
||||
@@ -155,8 +155,8 @@ protected:
|
||||
uv_mutex_t m_clientsListLock;
|
||||
std::vector<Client*> m_preallocatedClients;
|
||||
Client* m_connectedClientsList;
|
||||
uint32_t m_numConnections;
|
||||
uint32_t m_numIncomingConnections;
|
||||
std::atomic<uint32_t> m_numConnections;
|
||||
std::atomic<uint32_t> m_numIncomingConnections;
|
||||
|
||||
uv_mutex_t m_bansLock;
|
||||
unordered_map<raw_ip, std::chrono::steady_clock::time_point> m_bans;
|
||||
|
||||
+43
-13
@@ -28,8 +28,8 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
|
||||
, m_finished(0)
|
||||
, m_listenPort(-1)
|
||||
, m_loopStopped{false}
|
||||
, m_numConnections(0)
|
||||
, m_numIncomingConnections(0)
|
||||
, m_numConnections{ 0 }
|
||||
, m_numIncomingConnections{ 0 }
|
||||
{
|
||||
int err = uv_loop_init(&m_loop);
|
||||
if (err) {
|
||||
@@ -37,10 +37,18 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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>
|
||||
// cppcheck-suppress functionStatic
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::~TCPServer()
|
||||
{
|
||||
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>
|
||||
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();
|
||||
|
||||
MutexLock lock(m_bansLock);
|
||||
@@ -372,8 +385,11 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer_nolock(Client* cl
|
||||
return false;
|
||||
}
|
||||
|
||||
client->m_connectRequest.data = client;
|
||||
err = uv_tcp_connect(&client->m_connectRequest, &client->m_socket, addr, on_connect);
|
||||
uv_connect_t* connect_request = reinterpret_cast<uv_connect_t*>(client->m_readBuf);
|
||||
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) {
|
||||
LOGERR(1, "failed to initiate tcp connection, error " << uv_err_name(err));
|
||||
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()
|
||||
{
|
||||
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>
|
||||
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);
|
||||
|
||||
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
|
||||
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) {
|
||||
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>
|
||||
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[READ_BUF_SIZE - 1] = '\0';
|
||||
}
|
||||
|
||||
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_next = nullptr;
|
||||
memset(&m_socket, 0, sizeof(m_socket));
|
||||
memset(&m_connectRequest, 0, sizeof(m_connectRequest));
|
||||
m_isV6 = false;
|
||||
m_isIncoming = false;
|
||||
m_readBufInUse = false;
|
||||
m_numRead = 0;
|
||||
m_addr = {};
|
||||
m_port = -1;
|
||||
m_addrString[0] = '\0';
|
||||
m_readBufInUse = false;
|
||||
m_numRead = 0;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
|
||||
+41
-2
@@ -32,7 +32,7 @@ namespace p2pool {
|
||||
#define STR2(X) STR(X)
|
||||
#define STR(X) #X
|
||||
|
||||
const char* VERSION = "v2.0 (built"
|
||||
const char* VERSION = "v2.1 (built"
|
||||
#if defined(__clang__)
|
||||
" with clang/" __clang_version__
|
||||
#elif defined(__GNUC__)
|
||||
@@ -349,7 +349,7 @@ bool resolve_host(std::string& host, bool& is_v6)
|
||||
addrinfo hints{};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
|
||||
addrinfo* r = nullptr;
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
+16
@@ -203,6 +203,22 @@ FORCEINLINE uint64_t seconds_since_epoch()
|
||||
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 robin_hood {
|
||||
|
||||
+1
-2
@@ -89,7 +89,6 @@ Wallet::Wallet(const Wallet& w)
|
||||
operator=(w);
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEqVarError
|
||||
Wallet& Wallet::operator=(const Wallet& w)
|
||||
{
|
||||
if (this == &w) {
|
||||
@@ -119,7 +118,7 @@ bool Wallet::decode(const char* address)
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i <= num_full_blocks; ++i) {
|
||||
|
||||
+7
-9
@@ -49,13 +49,13 @@ ZMQReader::ZMQReader(const char* address, uint32_t zmq_port, MinerCallbackHandle
|
||||
|
||||
if (!m_publisherPort) {
|
||||
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);
|
||||
if (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);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(1, "exception " << e.what() << ", aborting");
|
||||
panic();
|
||||
LOGERR(1, "exception " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +103,7 @@ void ZMQReader::run()
|
||||
zmq_msg_t message;
|
||||
int rc = zmq_msg_init(&message);
|
||||
if (rc != 0) {
|
||||
throw zmq::error_t();
|
||||
throw zmq::error_t(errno);
|
||||
}
|
||||
|
||||
LOGINFO(1, "worker thread ready");
|
||||
@@ -112,7 +111,7 @@ void ZMQReader::run()
|
||||
do {
|
||||
rc = zmq_msg_recv(&message, m_subscriber, 0);
|
||||
if (rc < 0) {
|
||||
throw zmq::error_t();
|
||||
throw zmq::error_t(errno);
|
||||
}
|
||||
|
||||
if (m_finished.load()) {
|
||||
@@ -125,8 +124,7 @@ void ZMQReader::run()
|
||||
zmq_msg_close(&message);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(1, "exception " << e.what() << ", aborting");
|
||||
panic();
|
||||
LOGERR(1, "exception " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +194,7 @@ void ZMQReader::parse(char* data, size_t size)
|
||||
using namespace rapidjson;
|
||||
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
+16
-49
@@ -3,12 +3,7 @@ project(p2pool_tests)
|
||||
|
||||
option(STATIC_LIBS "Use locally built libuv and libzmq static libs" OFF)
|
||||
|
||||
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)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0")
|
||||
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)
|
||||
add_definitions(-DWITH_RANDOMX)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
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()
|
||||
include(cmake/flags.cmake)
|
||||
|
||||
set(HEADERS
|
||||
)
|
||||
@@ -74,7 +28,7 @@ set(SOURCES
|
||||
src/keccak_tests.cpp
|
||||
src/main.cpp
|
||||
src/pool_block_tests.cpp
|
||||
src/varint_tests.cpp
|
||||
src/util_tests.cpp
|
||||
src/wallet_tests.cpp
|
||||
../external/src/cryptonote/crypto-ops-data.c
|
||||
../external/src/cryptonote/crypto-ops.c
|
||||
@@ -160,6 +114,19 @@ endif()
|
||||
|
||||
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})
|
||||
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}>)
|
||||
|
||||
@@ -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()
|
||||
@@ -55,7 +55,7 @@ TEST(hash, empty)
|
||||
hash h;
|
||||
ASSERT_EQ(h.empty(), true);
|
||||
|
||||
for (int i = 0; i < HASH_SIZE; ++i) {
|
||||
for (size_t i = 0; i < HASH_SIZE; ++i) {
|
||||
hash h2;
|
||||
h2.h[i] = 1;
|
||||
ASSERT_EQ(h2.empty(), false);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
TEST(varint, read_write)
|
||||
TEST(util, varint)
|
||||
{
|
||||
std::vector<uint8_t> v;
|
||||
v.reserve(16);
|
||||
@@ -82,4 +82,12 @@ TEST(varint, read_write)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user