Compare commits

..

26 Commits

Author SHA1 Message Date
SChernykh 9fee040ce0 p2pool v4.14 2026-03-01 10:01:44 +01:00
SChernykh ca39b36337 Stratum: reset workers counters on synchronized 2026-02-28 17:22:53 +01:00
SChernykh 7923f84233 Stratum: added sidechain/stratum shares display to workers command 2026-02-25 19:39:34 +01:00
SChernykh 7667f9d21e Refactored parameter parsing 2026-02-25 11:01:44 +01:00
SChernykh 0741ad1c07 Build scripts: updated versions 2026-02-25 07:32:34 +01:00
SChernykh f05ce6f697 Fixed SOCKS5 proxy detection
`std::stoul` can throw an exception, so don't use it.
2026-02-24 20:35:44 +01:00
KingJulien1st 23d3a24bc4 Add HAProxy PROXY Protocol v2 support (#399) 2026-02-22 22:17:32 +01:00
SChernykh 2cc5ba2fb9 CI: fixed msan build 2026-02-20 16:22:51 +01:00
SChernykh 93e3c07a18 Updated BoringSSL to v0.20260211.0 2026-02-17 12:08:35 +01:00
SChernykh 7f0be0bcf5 Updated RandomX 2026-02-15 14:06:31 +01:00
jpk68 f8310f27b8 Specify SOCKS5 proxy type in Tor docs 2026-02-12 22:13:56 +01:00
SChernykh 160ebd4289 Updated libuv to v1.52.0 2026-02-11 13:09:53 +01:00
SChernykh 6d6c12c1e8 Added SOCKS5 proxy type command line parameter
- Auto-detect by default, based on the port number
- Don't run TOR-specific code if it's not the TOR proxy
2026-02-10 21:32:01 +01:00
SChernykh cf1c88b907 Support IPv6 for ZMQ 2026-02-07 13:41:44 +01:00
SChernykh 6449a78863 Don't init gRPC if it's not used 2026-02-06 18:57:24 +01:00
SChernykh d966088470 Updated BoringSSL patch 2026-02-05 18:42:51 +01:00
SChernykh 5faec12678 Updated BoringSSL to v0.20260204.0 2026-02-05 17:18:36 +01:00
SChernykh 1bcddc8329 Build scripts: updated versions 2026-02-04 20:03:15 +01:00
SChernykh 0905b23123 Updated cppzmq and libzmq 2026-02-04 00:42:59 +01:00
SChernykh 64914566c0 Updated RandomX and miniupnp 2026-02-03 18:11:18 +01:00
SChernykh ab80f55698 Fixed whitespace 2026-01-26 22:47:17 +01:00
User0 31860f2e65 docs(root): fix note block about nano and mini in readme.md (#393) 2026-01-26 21:06:15 +01:00
jpk68 6e7311a83c Update docs (#392) 2026-01-24 13:36:20 +01:00
SChernykh e0a6daa5c7 Updated curl to 8.18.0 2026-01-07 16:37:27 +01:00
SChernykh 313fb64b41 Updated copyright 2026-01-01 22:13:05 +01:00
SChernykh 096e2e086b Updated DarkFi information 2025-12-29 19:15:41 +01:00
79 changed files with 786 additions and 526 deletions
-95
View File
@@ -326,101 +326,6 @@ jobs:
name: p2pool-${{ matrix.config.os }}-aarch64
path: build/p2pool
build-ubuntu-riscv64:
timeout-minutes: 60
runs-on: ${{ matrix.config.os }}
strategy:
matrix:
config:
- {os: ubuntu-22.04, flags: "-fuse-linker-plugin -ffunction-sections"}
steps:
- name: Setup Alpine Linux
uses: jirutka/setup-alpine@v1
with:
arch: riscv64
branch: latest-stable
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y git build-essential cmake gcc-riscv64-linux-gnu g++-riscv64-linux-gnu binutils-riscv64-linux-gnu xz-utils
sudo cp /usr/riscv64-linux-gnu/lib/* /home/runner/rootfs/alpine-latest-riscv64/lib
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build libcurl
run: |
cd external/src/curl
cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../cmake/riscv64_toolchain.cmake -DCMAKE_C_FLAGS="-Os -flto=auto ${{ matrix.config.flags }}" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_DISABLE_INSTALL=ON -DCURL_ENABLE_EXPORT_TARGET=OFF -DCURL_DISABLE_HEADERS_API=ON -DCURL_DISABLE_BINDLOCAL=ON -DBUILD_LIBCURL_DOCS=OFF -DBUILD_MISC_DOCS=OFF -DENABLE_CURL_MANUAL=OFF -DCURL_ZLIB=OFF -DCURL_BROTLI=OFF -DCURL_ZSTD=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DCURL_DISABLE_WEBSOCKETS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF -DCURL_DISABLE_TESTS=ON -DUSE_NGHTTP2=OFF -DBUILD_EXAMPLES=OFF -DP2POOL_BORINGSSL=ON -DCURL_DISABLE_SRP=ON -DCURL_DISABLE_AWS=ON -DCURL_DISABLE_BASIC_AUTH=ON -DCURL_DISABLE_BEARER_AUTH=ON -DCURL_DISABLE_KERBEROS_AUTH=ON -DCURL_DISABLE_NEGOTIATE_AUTH=ON -DOPENSSL_INCLUDE_DIR=../grpc/third_party/boringssl-with-bazel/include
make -j$(nproc)
- name: Build libuv
run: |
cd external/src/libuv
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../cmake/riscv64_toolchain.cmake -DCMAKE_C_FLAGS='-Os -flto=auto ${{ matrix.config.flags }}' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
make -j$(nproc)
- name: Build libzmq
run: |
cd external/src/libzmq
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../../cmake/riscv64_toolchain.cmake -DCMAKE_C_FLAGS='-Os -flto=auto ${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='-Os -flto=auto ${{ matrix.config.flags }}' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc)
- name: Build p2pool
run: |
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/riscv64_toolchain.cmake -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON -DARCH_ID=riscv64 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc) p2pool
- name: Run self-test
shell: alpine.sh {0}
run: build/p2pool --test
- name: Build RandomX tests
run: |
cd build
make -j$(nproc) randomx-tests
- name: Run RandomX tests
shell: alpine.sh {0}
run: build/external/src/RandomX/randomx-tests
- name: Build tests
run: |
cd tests
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../../cmake/riscv64_toolchain.cmake -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON -DARCH_ID=riscv64 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc) p2pool_tests
- name: Prepare test data
run: |
cd tests/build
unxz *.xz
- name: Run tests
shell: alpine.sh {0}
run: |
cd tests/build
./p2pool_tests
- name: Archive binary
uses: actions/upload-artifact@v4
with:
name: p2pool-${{ matrix.config.os }}-riscv64
path: build/p2pool
build-windows-msys2:
timeout-minutes: 60
+1 -1
View File
@@ -91,7 +91,7 @@ jobs:
sync-test-ubuntu-msan:
timeout-minutes: 60
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
steps:
- name: Install dependencies
+5 -9
View File
@@ -99,13 +99,10 @@ In order to continue mining on P2Pool, you must update both Monero and P2Pool so
- It is highly recommended that you create a separate restricted user account (in your OS) for mining. While P2Pool has been battle-tested for a long time now, any software may have unknown bugs/vulnerabilities.
- You can mine to a primary wallet address (the one starting with `4`) for mining. If you want to mine to a subaddress, you will need to provide both the main address (starting with 4) and the subaddress (starting with 8) using `--wallet` and `--subaddress` command line parameters.
- You can add the `--mini` or `--nano` parameter to your P2Pool command to connect to the respective sidechain.
> [!NOTE]
>
> You cannot use both `--mini` and `--nano` together
>
> Using `--mini` will change the p2p port to 37888.
>
> Using `--nano` will change the p2p port to 37890.
> [!NOTE]
> You cannot use both `--mini` and `--nano` together<br>
> Using `--mini` will change the p2p port to 37888.<br>
> Using `--nano` will change the p2p port to 37890.<br>
- Check that ports 18080 (Monero p2p port) and 37889/37888/37890 (P2Pool default/mini/nano p2p port) are open in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine.
- You can connect multiple miners to the same P2Pool node. The more the better!
- The steps below assume that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup.
@@ -117,7 +114,6 @@ In order to continue mining on P2Pool, you must update both Monero and P2Pool so
- [Cake Wallet v4.4.5 and newer](https://cakewallet.com/)
- [Monero.com by Cake Wallet](https://monero.com/)
- [Feather Wallet v2.1.0 and newer](https://featherwallet.org/)
- [MyMonero](https://mymonero.com/)
### GUI for P2Pool
@@ -129,7 +125,7 @@ Merge mining is available in P2Pool since the fork that happened on October 12th
Blockchains that will support [Merge mining RPC API](https://github.com/SChernykh/p2pool/blob/master/docs/MERGE_MINING.MD#proposed-rpc-api):
- [Townforge](https://townforge.net/) supports it in their [tmp-mm branch](https://git.townforge.net/townforge/townforge/src/branch/tmp-mm) (not released yet)
- [DarkFi](https://dark.fi/) is going to support it, but it's [not ready yet](https://github.com/darkrenaissance/darkfi/issues/244)
- [DarkFi](https://dark.fi/) supports it in their [testnet](https://dark.fi/book/testnet/merge-mining.html)
```
p2pool.exe --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine IP:port YOUR_WALLET_ADDRESS_ON_ANOTHER_BLOCKCHAIN
```
+3
View File
@@ -29,6 +29,7 @@
--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)
--rpc-login Specify username[:password] required for Monero RPC server
--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections
--socks5-proxy-type The type of SOCKS5 proxy. Can be one of the following values: auto, plain, tor. Default is auto (auto-detect by the port number)
--no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)
--p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections
--no-upnp Disable UPnP port forwarding
@@ -40,6 +41,8 @@
--tls-cert-key file Load TLS certificate private key from "file" in the PEM format
--rpc-ssl Enable SSL on RPC connections to the Monero node
--rpc-ssl-fingerprint base64-encoded fingerprint of the Monero node's certificate (optional, use it for certificate pinning)
--stratum-proxy-protocol Enable HAProxy PROXY protocol v2 for incoming Stratum connections (use with HAProxy send-proxy-v2)
--p2p-proxy-protocol Enable HAProxy PROXY protocol v2 for incoming P2P connections (use with HAProxy send-proxy-v2)
--no-stratum-http Disable HTTP on Stratum ports
--full-validation Enables full share validation / increases CPU usage
--onion-address Tell other peers to use this .onion address to connect to this node through TOR
+2 -1
View File
@@ -3,6 +3,7 @@
P2Pool has several command-line options that should be used for TOR setup:
- `--socks5 IP:port` to specify your TOR proxy address (usually `127.0.0.1:9050` if you installed TOR on the same PC)
- `--socks5-proxy-type tor` to specify the type of SOCKS5 proxy being used
- `--no-dns` to disable all DNS queries and prevent DNS leaks. P2Pool only ever makes DNS requests to get a list of seed nodes, to resolve your Monero node's domain (if it's not set as an IP address), and to resolve manually added peers
- `--no-upnp` to disable UPnP requests (they are sent to your router, so use this option if you are not on your home network)
- `--onion-address` your hidden service's address (without port number). This address will be broadcast to other peers when you mine a share in P2Pool. This is to prevent address spamming - you have to mine a real share to be able to broadcast your TOR address.
@@ -27,5 +28,5 @@ P2Pool has several command-line options that should be used for TOR setup:
## Command line example
```
./p2pool --host MONERO_NODE_IP --wallet YOUR_WALLET --socks5 127.0.0.1:9050 --no-dns --no-upnp --onion-address ADDRESS_FROM_HOSTNAME_FILE
./p2pool --host MONERO_NODE_IP --wallet YOUR_WALLET --socks5 127.0.0.1:9050 --socks5-proxy-type tor --no-dns --no-upnp --onion-address ADDRESS_FROM_HOSTNAME_FILE
```
+1 -2
View File
@@ -239,7 +239,6 @@ Wallets with confirmed P2Pool support<br>
<li><a href="https://play.google.com/store/apps/details?id=com.m2049r.xmrwallet" target="_blank">Monerujo v3.0.2 "Fluorine Fermi"</a> and newer
<li><a href="https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet" target="_blank">Cake Wallet v4.4.5</a> and newer
<li><a href="https://featherwallet.org/" target="_blank">Feather Wallet v2.1.0</a> and newer
<li><a href="https://mymonero.com/" target="_blank">MyMonero</a>
</ul>
It's highly recommended to create a new wallet for mining because wallet addresses are public on p2pool. You can mine to a primary wallet address (the one starting with `4`) for mining. If you want to mine to a subaddress, you will need to provide both the main address (starting with 4) and the subaddress (starting with 8) using "--wallet" and "--subaddress" command line parameters.
</details>
@@ -315,4 +314,4 @@ Donate to support the project:<br><span style="font-size:0.9rem;color:#b0b0b0;">
&nbsp;
</div>
</body>
</html>
</html>
+1 -2
View File
@@ -239,7 +239,6 @@ Wallets with confirmed P2Pool support<br>
<li><a href="https://play.google.com/store/apps/details?id=com.m2049r.xmrwallet" target="_blank">Monerujo v3.0.2 "Fluorine Fermi"</a> and newer
<li><a href="https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet" target="_blank">Cake Wallet v4.4.5</a> and newer
<li><a href="https://featherwallet.org/" target="_blank">Feather Wallet v2.1.0</a> and newer
<li><a href="https://mymonero.com/" target="_blank">MyMonero</a>
</ul>
It's highly recommended to create a new wallet for mining because wallet addresses are public on p2pool. You can mine to a primary wallet address (the one starting with `4`) for mining. If you want to mine to a subaddress, you will need to provide both the main address (starting with 4) and the subaddress (starting with 8) using "--wallet" and "--subaddress" command line parameters.
</details>
@@ -315,4 +314,4 @@ Donate to support the project:<br><span style="font-size:0.9rem;color:#b0b0b0;">
&nbsp;
</div>
</body>
</html>
</html>
+1 -2
View File
@@ -242,7 +242,6 @@ Wallets with confirmed P2Pool support<br>
<li><a href="https://play.google.com/store/apps/details?id=com.m2049r.xmrwallet" target="_blank">Monerujo v3.0.2 "Fluorine Fermi"</a> and newer
<li><a href="https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet" target="_blank">Cake Wallet v4.4.5</a> and newer
<li><a href="https://featherwallet.org/" target="_blank">Feather Wallet v2.1.0</a> and newer
<li><a href="https://mymonero.com/" target="_blank">MyMonero</a>
</ul>
It's highly recommended to create a new wallet for mining because wallet addresses are public on p2pool. You can mine to a primary wallet address (the one starting with `4`) for mining. If you want to mine to a subaddress, you will need to provide both the main address (starting with 4) and the subaddress (starting with 8) using "--wallet" and "--subaddress" command line parameters.
</details>
@@ -318,4 +317,4 @@ Donate to support the project:<br><span style="font-size:0.9rem;color:#b0b0b0;">
&nbsp;
</div>
</body>
</html>
</html>
+7 -7
View File
@@ -1,5 +1,5 @@
diff --git a/crypto/rand/windows.cc b/crypto/rand/windows.cc
index 6a93a2d84..f75112b4f 100644
index ebd0d4afd..65e877f0e 100644
--- a/crypto/rand/windows.cc
+++ b/crypto/rand/windows.cc
@@ -24,6 +24,7 @@
@@ -8,11 +8,11 @@ index 6a93a2d84..f75112b4f 100644
#include <windows.h>
+#include <wincrypt.h>
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@@ -57,16 +58,39 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
using namespace bssl;
@@ -59,16 +60,39 @@ void bssl::CRYPTO_sysrand(uint8_t *out, size_t requested) {
// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
typedef BOOL (WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData);
typedef BOOL(WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData);
static ProcessPrngFunction g_processprng_fn = nullptr;
+static HCRYPTPROV g_hCryptProv = 0;
+
@@ -21,7 +21,7 @@ index 6a93a2d84..f75112b4f 100644
+ return CryptGenRandom(g_hCryptProv, cbData, pbData);
+}
static void init_processprng(void) {
static void init_processprng() {
HMODULE hmod = LoadLibraryW(L"bcryptprimitives");
- if (hmod == nullptr) {
- abort();
@@ -54,4 +54,4 @@ index 6a93a2d84..f75112b4f 100644
+ abort();
}
void CRYPTO_init_sysrand(void) {
void bssl::CRYPTO_init_sysrand() {
+10 -10
View File
@@ -3,14 +3,14 @@ set -e
# Software versions to install
_7ZIP_VERSION=2501
BINUTILS_VERSION=2_45_1
_7ZIP_VERSION=2600
BINUTILS_VERSION=2_46
CLANG_VERSION=21.1.8
CMAKE_VERSION=4.2.1
CMAKE_VERSION=4.2.3
FREEBSD_VERSION=12.4
GCC_VERSION=15.2.0
GLIBC_VERSION=2.42
LINUX_HEADERS_VERSION=6.18.1
GLIBC_VERSION=2.43
LINUX_HEADERS_VERSION=6.19.3
MACOSX_SDK_VERSION=26.1
OSXCROSS_VERSION=2bc739ebe45db5d72e176d2a4e1c7dd95464e8e2
MAKE_VERSION=4.4.1
@@ -18,12 +18,12 @@ MINGW_VERSION=13.0.0
XZ_VERSION=5.8.2
TAR_VERSION=1.35
_7ZIP_SHA256="4ca3b7c6f2f67866b92622818b58233dc70367be2f36b498eb0bdeaaa44b53f4"
CMAKE_SHA256="c059bff1e97a2b6b5b0c0872263627486345ad0ed083298cb21cff2eda883980"
_7ZIP_SHA256="c74dc4a48492cde43f5fec10d53fb2a66f520e4a62a69d630c44cb22c477edc6"
CMAKE_SHA256="5bb505d5e0cca0480a330f7f27ccf52c2b8b5214c5bba97df08899f5ef650c23"
FREEBSD_AARCH64_SHA256="6c401819bfb93e810c9f9aa670a1e4685f924df5e7e0c9c6397dd6c16c954fa2"
FREEBSD_X86_64_SHA256="581c7edacfd2fca2bdf5791f667402d22fccd8a5e184635e0cac075564d57aa8"
GLIBC_SHA256="d1775e32e4628e64ef930f435b67bb63af7599acb6be2b335b9f19f16509f17f"
HEADERS_SHA256="d0a78bf3f0d12aaa10af3b5adcaed5bc767b5b78705e5ef885d5e930b72e25d5"
GLIBC_SHA256="d9c86c6b5dbddb43a3e08270c5844fc5177d19442cf5b8df4be7c07cd5fa3831"
HEADERS_SHA256="0e474968adfcbee32916fd01a89d8ccfd1168d8d32569e76a5c664c793198ebe"
MACOSX_SDK_SHA256="beee7212d265a6d2867d0236cc069314b38d5fb3486a6515734e76fa210c784c"
MAKE_SHA256="dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3"
TAR_SHA256="4d62ff37342ec7aed748535323930c7cf94acf71c3591882b26a7ea50f3edc16"
@@ -33,7 +33,7 @@ echo "Install prerequisites"
export DEBIAN_FRONTEND=noninteractive
apt-get update && apt-get upgrade -yq --no-install-recommends
apt-get install -yq --no-install-recommends ca-certificates curl bzip2 flex texinfo bison ninja-build python3 file rsync xz-utils gawk gettext patch git gcc g++
apt-get install -yq --no-install-recommends ca-certificates curl bzip2 flex texinfo bison ninja-build python3 python3-yaml file rsync xz-utils gawk gettext patch git gcc g++
echo "Cloning the P2Pool repository in background"
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
* Portions Copyright (c) 2012-2013 The Cryptonote developers
* Portions Copyright (c) 2014-2021 The Monero Project
* Portions Copyright (c) 2021 XMRig <https://github.com/xmrig>
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+2 -2
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021 hyc <https://github.com/hyc>
*
* This program is free software: you can redistribute it and/or modify
@@ -35,7 +35,7 @@ static constexpr int DEFAULT_BACKLOG = 1;
namespace p2pool {
ConsoleCommands::ConsoleCommands(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, ConsoleClient::allocate, std::string())
: TCPServer(DEFAULT_BACKLOG, ConsoleClient::allocate, std::string(), Params::ProxyType::INVALID)
, m_pool(pool)
, m_tty{}
, m_stdin_pipe{}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+10 -3
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -89,6 +89,7 @@ void p2pool_usage()
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)\n"
"--rpc-login Specify username[:password] required for Monero RPC server\n"
"--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections\n"
"--socks5-proxy-type The type of SOCKS5 proxy. Can be one of the following values: auto, plain, tor. Default is auto (auto-detect by the port number)\n"
"--no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)\n"
"--p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections\n"
#ifdef WITH_UPNP
@@ -104,6 +105,8 @@ void p2pool_usage()
"--rpc-ssl Enable SSL on RPC connections to the Monero node\n"
"--rpc-ssl-fingerprint base64-encoded fingerprint of the Monero node's certificate (optional, use it for certificate pinning)\n"
#endif
"--stratum-proxy-protocol Enable HAProxy PROXY protocol v2 for incoming Stratum connections (use with HAProxy send-proxy-v2)\n"
"--p2p-proxy-protocol Enable HAProxy PROXY protocol v2 for incoming P2P connections (use with HAProxy send-proxy-v2)\n"
"--no-stratum-http Disable HTTP on Stratum ports\n"
"--full-validation Enables full share validation / increases CPU usage\n"
"--onion-address Tell other peers to use this .onion address to connect to this node through TOR\n"
@@ -343,7 +346,9 @@ int main(int argc, char* argv[])
}
#ifdef WITH_GRPC
grpc_init();
if (params.grpc_needed()) {
grpc_init();
}
#endif
#ifdef WITH_TLS
@@ -362,7 +367,9 @@ int main(int argc, char* argv[])
}
#ifdef WITH_GRPC
grpc_shutdown();
if (params.grpc_needed()) {
grpc_shutdown();
}
#endif
curl_global_cleanup();
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+4 -4
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
, m_auxWallet(wallet)
, m_pool(pool)
, m_tariJobParams{}
, m_server(new TariServer(pool->params().m_socks5Proxy))
, m_server(new TariServer(pool->params().m_socks5Proxy, pool->params().m_socks5ProxyType))
, m_hostStr(host)
, m_workerStop(0)
, m_pushBlockStop(0)
@@ -863,8 +863,8 @@ void MergeMiningClientTari::run()
// TariServer and TariClient are simply a proxy from a localhost TCP port to the external Tari node
// This is needed for SOCKS5 proxy support (gRPC library doesn't support it natively)
MergeMiningClientTari::TariServer::TariServer(const std::string& socks5Proxy)
: TCPServer(1, MergeMiningClientTari::TariClient::allocate, socks5Proxy)
MergeMiningClientTari::TariServer::TariServer(const std::string& socks5Proxy, Params::ProxyType socks5ProxyType)
: TCPServer(1, MergeMiningClientTari::TariClient::allocate, socks5Proxy, socks5ProxyType)
, m_TariNodeIsV6(false)
, m_TariNodeHost()
, m_TariNodePort(0)
+2 -2
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -83,7 +83,7 @@ private:
struct TariServer : public TCPServer
{
explicit TariServer(const std::string& socks5Proxy);
TariServer(const std::string& socks5Proxy, Params::ProxyType socks5ProxyType);
~TariServer() {}
[[nodiscard]] bool start();
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+24 -9
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ static constexpr hash seed_onion_nodes[] = {
};
P2PServer::P2PServer(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, P2PClient::allocate, pool->params().m_socks5Proxy)
: TCPServer(DEFAULT_BACKLOG, P2PClient::allocate, pool->params().m_socks5Proxy, pool->params().m_socks5ProxyType, pool->params().m_p2pProxyProtocol)
, m_pool(pool)
, m_cache(pool->params().m_blockCache ? new BlockCache(pool->params()) : nullptr)
, m_cacheLoaded(false)
@@ -426,14 +426,16 @@ void P2PServer::update_peer_connections()
uint32_t num_outgoing = m_numConnections - m_numIncomingConnections;
// Try to have at least N/2 outgoing onion connections
if (!m_socks5Proxy.empty()) {
// Try to have at least N/2 (or N if clearnet P2P is disabled) outgoing onion connections
if (!m_socks5Proxy.empty() && (m_socks5ProxyType == Params::ProxyType::TOR)) {
std::vector<hash> pubkeys = m_pool->side_chain().seen_onion_pubkeys();
// Add seed nodes
pubkeys.insert(pubkeys.end(), seed_onion_nodes, seed_onion_nodes + array_size(seed_onion_nodes));
for (uint32_t i = m_numOnionConnections, n = N / 2; (i < n) && !pubkeys.empty();) {
const uint32_t n = m_pool->params().m_noClearnetP2P ? N : (N / 2);
for (uint32_t i = m_numOnionConnections; (i < n) && !pubkeys.empty();) {
const uint64_t k = get_random64() % pubkeys.size();
const std::string addr = to_onion_v3(pubkeys[k]);
@@ -727,8 +729,21 @@ void P2PServer::load_peer_list()
}
// Finally load peers from p2pool_peers.txt and p2pool_onion_peers.txt
for (size_t i = 0, n = (m_socks5Proxy.empty() ? 1 : 2); i < n; ++i) {
const std::string path = m_pool->params().m_dataDir + (i ? saved_onion_peer_list_file_name : saved_peer_list_file_name);
std::vector<std::string> paths;
paths.resize(Params::ProxyType::MAX);
paths[Params::ProxyType::PLAIN] = saved_peer_list_file_name;
if (!m_socks5Proxy.empty() && (m_socks5ProxyType == Params::ProxyType::TOR)) {
paths[Params::ProxyType::TOR] = saved_onion_peer_list_file_name;
}
for (int i = Params::ProxyType::PLAIN; i < Params::ProxyType::MAX; ++i) {
const std::string& path = paths[i];
if (path.empty()) {
continue;
}
std::ifstream f(path);
@@ -740,7 +755,7 @@ void P2PServer::load_peer_list()
std::getline(f, address);
if (!address.empty()) {
if (i > 0) {
if (i == Params::ProxyType::TOR) {
const hash h = from_onion_v3(address);
if (!h.empty()) {
pubkeys.emplace_back(h);
@@ -756,7 +771,7 @@ void P2PServer::load_peer_list()
}
f.close();
if (i > 0) {
if (i == Params::ProxyType::TOR) {
s.add_onion_pubkeys(pubkeys);
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+338 -264
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,11 @@
#include "p2p_server.h"
#include <fstream>
#ifdef WITH_GRPC
#include "merge_mining_client.h"
#include "merge_mining_client_tari.h"
#endif
LOG_CATEGORY(Params)
void p2pool_usage();
@@ -32,275 +37,13 @@ static constexpr uint64_t MAX_STRATUM_BAN_TIME = (UINT64_C(1) << 34) - 1;
Params::Params(const std::vector<std::vector<std::string>>& args)
{
auto has1 = [](const auto& v) { return (v.size() > 1) && !v[1].empty();};
auto has2 = [](const auto& v) { return (v.size() > 2) && !v[2].empty();};
for (const auto& arg : args) {
// Ignore empty parameters
if (arg.empty() || arg[0].empty()) {
continue;
}
bool ok = false;
if ((arg[0] == "host") && has1(arg)) {
const char* address = arg[1].c_str();
if (m_hosts.empty()) {
m_hosts.emplace_back();
m_hosts.back().m_address = address;
}
else {
const Host& h = m_hosts.back();
m_hosts.emplace_back(address, h.m_rpcPort, h.m_zmqPort, "");
}
ok = true;
}
if ((arg[0] == "rpc-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
if ((arg[0] == "zmq-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_zmqPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
if (arg[0] == "light-mode") {
m_lightMode = true;
ok = true;
}
if ((arg[0] == "wallet") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_mainWallet.decode(s)) {
LOGERR(1, "Wallet " << s << " failed to decode");
}
ok = true;
}
if ((arg[0] == "subaddress") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_subaddress.decode(s)) {
LOGERR(1, "Subaddress " << s << " failed to decode");
}
ok = true;
}
if ((arg[0] == "stratum") && has1(arg)) {
m_stratumAddresses = arg[1];
ok = true;
}
if ((arg[0] == "stratum-ban-time") && has1(arg)) {
m_stratumBanTime = strtoull(arg[1].c_str(), nullptr, 10);
ok = true;
}
if ((arg[0] == "p2p") && has1(arg)) {
m_p2pAddresses = arg[1];
ok = true;
}
if ((arg[0] == "addpeers") && has1(arg)) {
m_p2pPeerList = arg[1];
ok = true;
}
if ((arg[0] == "loglevel") && has1(arg)) {
const int level = std::min(std::max<int>(static_cast<int>(strtol(arg[1].c_str(), nullptr, 10)), 0), log::MAX_GLOBAL_LOG_LEVEL);
log::GLOBAL_LOG_LEVEL = level;
ok = true;
}
if ((arg[0] == "data-dir") && has1(arg)) {
m_dataDir = arg[1];
ok = true;
}
if ((arg[0] == "log-file") && has1(arg)) {
m_logFilePath = arg[1];
ok = true;
}
if ((arg[0] == "sidechain-config") && has1(arg)) {
m_sidechainConfig = arg[1];
ok = true;
}
if ((arg[0] == "data-api") && has1(arg)) {
m_apiPath = arg[1];
ok = true;
}
if ((arg[0] == "local-api") || (arg[0] == "stratum-api")) {
m_localStats = true;
ok = true;
}
if (arg[0] == "no-cache") {
m_blockCache = false;
ok = true;
}
if (arg[0] == "no-color") {
log::CONSOLE_COLORS = false;
ok = true;
}
#ifdef WITH_RANDOMX
if (arg[0] == "no-randomx") {
m_disableRandomX = true;
ok = true;
}
#endif
if (((arg[0] == "out-peers") || (arg[0] == "outpeers")) && has1(arg)) {
m_maxOutgoingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
ok = true;
}
if (((arg[0] == "in-peers") || (arg[0] == "inpeers")) && has1(arg)) {
m_maxIncomingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
ok = true;
}
if ((arg[0] == "start-mining") && has1(arg)) {
m_minerThreads = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 64UL);
ok = true;
}
if (arg[0] == "mini") {
m_mini = true;
ok = true;
}
if (arg[0] == "nano") {
m_nano = true;
ok = true;
}
if (arg[0] == "no-autodiff") {
m_autoDiff = false;
ok = true;
}
if ((arg[0] == "rpc-login") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcLogin = arg[1];
ok = true;
}
#ifdef WITH_TLS
if (arg[0] == "rpc-ssl") {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcSSL = true;
ok = true;
}
if ((arg[0] == "rpc-ssl-fingerprint") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcSSL_Fingerprint = arg[1];
ok = true;
}
#endif
if ((arg[0] == "socks5") && has1(arg)) {
m_socks5Proxy = arg[1];
ok = true;
}
if (arg[0] == "no-dns") {
m_dns = false;
disable_resolve_host = true;
ok = true;
}
if ((arg[0] == "p2p-external-port") && has1(arg)) {
m_p2pExternalPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
#ifdef WITH_UPNP
if ((arg[0] == "no-upnp") || (arg[0] == "no-igd")) {
m_upnp = false;
ok = true;
}
if (arg[0] == "upnp-stratum") {
m_upnpStratum = true;
ok = true;
}
#endif
if ((arg[0] == "merge-mine") && has1(arg) && has2(arg)) {
m_mergeMiningHosts.emplace_back(arg[1], arg[2]);
ok = true;
}
#ifdef WITH_TLS
if ((arg[0] == "tls-cert") && has1(arg)) {
m_tlsCert = arg[1];
ok = true;
}
if ((arg[0] == "tls-cert-key") && has1(arg)) {
m_tlsCertKey = arg[1];
ok = true;
}
#endif
if (arg[0] == "no-stratum-http") {
m_enableStratumHTTP = false;
ok = true;
}
#ifdef WITH_MERGE_MINING_DONATION
if ((arg[0] == "adkf") && has1(arg)) {
m_authorKeyFile = arg[1];
ok = true;
}
#endif
if (arg[0] == "full-validation") {
m_enableFullValidation = true;
ok = true;
}
if ((arg[0] == "onion-address") && has1(arg)) {
m_onionAddress = arg[1];
ok = true;
}
if (arg[0] == "no-clearnet-p2p") {
m_noClearnetP2P = true;
ok = true;
}
if (!ok) {
if (!process_arg(arg)) {
fprintf(stderr, "Unknown or invalid command line parameter \"%s\"\n\n", arg[0].c_str());
p2pool_usage();
throw std::exception();
@@ -421,6 +164,318 @@ Params::Params(const std::vector<std::vector<std::string>>& args)
else {
fixup_path(m_dataDir);
}
// Detect the proxy type
if (!m_socks5Proxy.empty() && (m_socks5ProxyType == ProxyType::AUTO)) {
m_socks5ProxyType = ProxyType::INVALID;
const size_t k = m_socks5Proxy.find_last_of(':');
if ((k != std::string::npos) && (k < m_socks5Proxy.length() - 1)) {
const unsigned long port = strtoul(m_socks5Proxy.substr(k + 1).c_str(), nullptr, 10);
if ((port > 0) && (port < 65536)) {
switch (port) {
case 9050:
m_socks5ProxyType = ProxyType::TOR;
break;
default:
m_socks5ProxyType = ProxyType::PLAIN;
break;
}
}
}
}
}
bool Params::process_arg(const std::vector<std::string>& arg)
{
if ((arg[0] == "host") && has1(arg)) {
const std::string& address = arg[1];
if (m_hosts.empty()) {
m_hosts.emplace_back();
m_hosts.back().m_address = address;
}
else {
const Host& h = m_hosts.back();
int32_t rpc_port = h.m_rpcPort;
int32_t zmq_port = h.m_zmqPort;
// Better not to use "h" here because emplace_back can reallocate
m_hosts.emplace_back(address, rpc_port, zmq_port, std::string());
}
return true;
}
if ((arg[0] == "rpc-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
return true;
}
if ((arg[0] == "zmq-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_zmqPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
return true;
}
if (arg[0] == "light-mode") {
m_lightMode = true;
return true;
}
if ((arg[0] == "wallet") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_mainWallet.decode(s)) {
LOGERR(1, "Wallet " << s << " failed to decode");
}
return true;
}
if ((arg[0] == "subaddress") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_subaddress.decode(s)) {
LOGERR(1, "Subaddress " << s << " failed to decode");
}
return true;
}
if ((arg[0] == "stratum") && has1(arg)) {
m_stratumAddresses = arg[1];
return true;
}
if ((arg[0] == "stratum-ban-time") && has1(arg)) {
m_stratumBanTime = strtoull(arg[1].c_str(), nullptr, 10);
return true;
}
if ((arg[0] == "p2p") && has1(arg)) {
m_p2pAddresses = arg[1];
return true;
}
if ((arg[0] == "addpeers") && has1(arg)) {
m_p2pPeerList = arg[1];
return true;
}
if ((arg[0] == "loglevel") && has1(arg)) {
const int level = std::min(std::max<int>(static_cast<int>(strtol(arg[1].c_str(), nullptr, 10)), 0), log::MAX_GLOBAL_LOG_LEVEL);
log::GLOBAL_LOG_LEVEL = level;
return true;
}
if ((arg[0] == "data-dir") && has1(arg)) {
m_dataDir = arg[1];
return true;
}
if ((arg[0] == "log-file") && has1(arg)) {
m_logFilePath = arg[1];
return true;
}
if ((arg[0] == "sidechain-config") && has1(arg)) {
m_sidechainConfig = arg[1];
return true;
}
if ((arg[0] == "data-api") && has1(arg)) {
m_apiPath = arg[1];
return true;
}
if ((arg[0] == "local-api") || (arg[0] == "stratum-api")) {
m_localStats = true;
return true;
}
if (arg[0] == "no-cache") {
m_blockCache = false;
return true;
}
if (arg[0] == "no-color") {
log::CONSOLE_COLORS = false;
return true;
}
#ifdef WITH_RANDOMX
if (arg[0] == "no-randomx") {
m_disableRandomX = true;
return true;
}
#endif
if (((arg[0] == "out-peers") || (arg[0] == "outpeers")) && has1(arg)) {
m_maxOutgoingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
return true;
}
if (((arg[0] == "in-peers") || (arg[0] == "inpeers")) && has1(arg)) {
m_maxIncomingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
return true;
}
if ((arg[0] == "start-mining") && has1(arg)) {
m_minerThreads = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 64UL);
return true;
}
if (arg[0] == "mini") {
m_mini = true;
return true;
}
if (arg[0] == "nano") {
m_nano = true;
return true;
}
if (arg[0] == "no-autodiff") {
m_autoDiff = false;
return true;
}
if ((arg[0] == "rpc-login") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcLogin = arg[1];
return true;
}
#ifdef WITH_TLS
if (arg[0] == "rpc-ssl") {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcSSL = true;
return true;
}
if ((arg[0] == "rpc-ssl-fingerprint") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcSSL_Fingerprint = arg[1];
return true;
}
#endif
if ((arg[0] == "socks5") && has1(arg)) {
m_socks5Proxy = arg[1];
return true;
}
if ((arg[0] == "socks5-proxy-type") && has1(arg)) {
const std::string s = tolower(arg[1]);
m_socks5ProxyType = ProxyType::INVALID;
if (s == "auto") m_socks5ProxyType = ProxyType::AUTO;
if (s == "plain") m_socks5ProxyType = ProxyType::PLAIN;
if (s == "tor") m_socks5ProxyType = ProxyType::TOR;
return m_socks5ProxyType != ProxyType::INVALID;
}
if (arg[0] == "no-dns") {
m_dns = false;
disable_resolve_host = true;
return true;
}
if ((arg[0] == "p2p-external-port") && has1(arg)) {
m_p2pExternalPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
return true;
}
#ifdef WITH_UPNP
if ((arg[0] == "no-upnp") || (arg[0] == "no-igd")) {
m_upnp = false;
return true;
}
if (arg[0] == "upnp-stratum") {
m_upnpStratum = true;
return true;
}
#endif
if ((arg[0] == "merge-mine") && has1(arg) && has2(arg)) {
m_mergeMiningHosts.emplace_back(arg[1], arg[2]);
return true;
}
#ifdef WITH_TLS
if ((arg[0] == "tls-cert") && has1(arg)) {
m_tlsCert = arg[1];
return true;
}
if ((arg[0] == "tls-cert-key") && has1(arg)) {
m_tlsCertKey = arg[1];
return true;
}
#endif
if (arg[0] == "no-stratum-http") {
m_enableStratumHTTP = false;
return true;
}
#ifdef WITH_MERGE_MINING_DONATION
if ((arg[0] == "adkf") && has1(arg)) {
m_authorKeyFile = arg[1];
return true;
}
#endif
if (arg[0] == "full-validation") {
m_enableFullValidation = true;
return true;
}
if ((arg[0] == "onion-address") && has1(arg)) {
m_onionAddress = arg[1];
return true;
}
if (arg[0] == "no-clearnet-p2p") {
m_noClearnetP2P = true;
return true;
}
if (arg[0] == "stratum-proxy-protocol") {
m_stratumProxyProtocol = true;
return true;
}
if (arg[0] == "p2p-proxy-protocol") {
m_p2pProxyProtocol = true;
return true;
}
return false;
}
bool Params::valid() const
@@ -473,9 +528,28 @@ bool Params::valid() const
return false;
}
if (m_socks5ProxyType == ProxyType::INVALID) {
LOGERR(1, "Invalid SOCKS5 proxy type. Check the --socks5 and --socks5-proxy-type parameters.");
return false;
}
return true;
}
#ifdef WITH_GRPC
bool Params::grpc_needed() const
{
for (const MergeMiningHost& h : m_mergeMiningHosts) {
if (h.m_host.find(MergeMiningClientTari::TARI_PREFIX) == 0) {
return true;
}
}
return false;
}
#endif
bool Params::Host::init_display_name(const Params& p)
{
m_displayName = m_address;
+27 -5
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,13 +31,17 @@ struct Params
explicit Params(const std::vector<std::vector<std::string>>& args);
bool valid() const;
[[nodiscard]] bool valid() const;
#ifdef WITH_GRPC
[[nodiscard]] bool grpc_needed() const;
#endif
struct Host
{
Host() : m_address("127.0.0.1"), m_rpcPort(18081), m_zmqPort(18083), m_rpcSSL(false) {}
Host(const char* address, int32_t rpcPort, int32_t zmqPort, const char* rpcLogin)
Host(const std::string& address, int32_t rpcPort, int32_t zmqPort, const std::string& rpcLogin)
: m_address(address)
, m_rpcPort(rpcPort)
, m_zmqPort(zmqPort)
@@ -45,9 +49,9 @@ struct Params
, m_rpcSSL(false)
{}
bool valid() const { return !m_address.empty() && m_rpcPort && m_zmqPort && (m_rpcPort != m_zmqPort); }
[[nodiscard]] bool valid() const { return !m_address.empty() && m_rpcPort && m_zmqPort && (m_rpcPort != m_zmqPort); }
bool init_display_name(const Params& p);
[[nodiscard]] bool init_display_name(const Params& p);
std::string m_address;
int32_t m_rpcPort;
@@ -104,7 +108,17 @@ struct Params
bool m_mini = false;
bool m_nano = false;
bool m_autoDiff = true;
std::string m_socks5Proxy;
enum ProxyType {
INVALID = -1,
AUTO = 0,
PLAIN = 1,
TOR = 2,
MAX = 3,
} m_socks5ProxyType = ProxyType::AUTO;
bool m_dns = true;
int32_t m_p2pExternalPort = 0;
#ifdef WITH_UPNP
@@ -135,6 +149,14 @@ struct Params
std::string m_onionAddress;
hash m_onionPubkey;
bool m_noClearnetP2P = false;
bool m_stratumProxyProtocol = false;
bool m_p2pProxyProtocol = false;
private:
[[nodiscard]] bool process_arg(const std::vector<std::string>& arg);
[[nodiscard]] static bool has1(const std::vector<std::string>& arg) { return (arg.size() > 1) && !arg[1].empty();}
[[nodiscard]] static bool has2(const std::vector<std::string>& arg) { return (arg.size() > 2) && !arg[2].empty();}
};
} // namespace p2pool
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+17
View File
@@ -1,3 +1,20 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(_MSC_VER) && defined(__cppcheck__)
// cppcheck chokes on rapidjson headers in Windows
#else
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+47 -2
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@ static constexpr int32_t BAN_THRESHOLD_POINTS = -15;
namespace p2pool {
StratumServer::StratumServer(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, StratumClient::allocate, std::string())
: TCPServer(DEFAULT_BACKLOG, StratumClient::allocate, std::string(), Params::ProxyType::INVALID, pool->params().m_stratumProxyProtocol)
, m_pool(pool)
, m_autoDiff(pool->params().m_autoDiff)
, m_enableFullValidation(pool->params().m_enableFullValidation)
@@ -70,6 +70,7 @@ StratumServer::StratumServer(p2pool* pool)
m_hashrateData[0] = { seconds_since_epoch(), 0 };
uv_mutex_init_checked(&m_resetShareCountersLock);
uv_mutex_init_checked(&m_blobsQueueLock);
uv_mutex_init_checked(&m_showWorkersLock);
uv_mutex_init_checked(&m_rngLock);
@@ -77,6 +78,9 @@ StratumServer::StratumServer(p2pool* pool)
m_extraNonce = get_random32();
uv_async_init_checked(&m_loop, &m_resetShareCountersAsync, on_reset_share_counters);
m_resetShareCountersAsync.data = this;
uv_async_init_checked(&m_loop, &m_blobsAsync, on_blobs_ready);
m_blobsAsync.data = this;
m_blobsQueue.reserve(2);
@@ -101,6 +105,7 @@ StratumServer::~StratumServer()
}
}
uv_mutex_destroy(&m_resetShareCountersLock);
uv_mutex_destroy(&m_blobsQueueLock);
uv_mutex_destroy(&m_showWorkersLock);
uv_mutex_destroy(&m_rngLock);
@@ -480,6 +485,8 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
update_auto_diff(client, share.m_timestamp, share.m_hashes);
++client->m_stratumShares;
// If this share is below sidechain difficulty, process it in this thread because it'll be quick
if (!share.m_highEnoughDifficulty && !m_enableFullValidation) {
on_share_found(&share.m_req);
@@ -565,6 +572,7 @@ void StratumServer::show_workers()
<< log::pad_right("uptime", 20)
<< log::pad_right("difficulty", 20)
<< log::pad_right("hashrate", 15)
<< log::pad_right("shares", 12)
<< "name"
);
@@ -585,11 +593,16 @@ void StratumServer::show_workers()
constexpr bool is_tls = false;
#endif
char shares_buf[16] = {};
log::Stream s(shares_buf);
s << c->m_sidechainShares << '/' << c->m_stratumShares << '\0';
LOGINFO(0, log::pad_right(static_cast<const char*>(c->m_addrString), addr_len + 8)
<< (is_tls ? "yes " : "no ")
<< 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)
<< log::pad_right(static_cast<const char*>(shares_buf), 12)
<< (c->m_rpcId ? c->m_customUser : "not logged in")
);
++n;
@@ -600,6 +613,22 @@ void StratumServer::show_workers()
void StratumServer::reset_share_counters()
{
MutexLock lock(m_resetShareCountersLock);
if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_resetShareCountersAsync))) {
uv_async_send(&m_resetShareCountersAsync);
}
}
void StratumServer::on_reset_share_counters()
{
check_event_loop_thread(__func__);
for (StratumClient* c = static_cast<StratumClient*>(m_connectedClientsList->m_next); c != m_connectedClientsList; c = static_cast<StratumClient*>(c->m_next)) {
c->m_stratumShares = 0;
c->m_sidechainShares = 0;
}
WriteLock lock(m_hashrateDataLock);
m_cumulativeHashesAtLastShare = m_cumulativeHashes;
@@ -1058,10 +1087,13 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
server->check_event_loop_thread(__func__);
bool share_found = false;
if (share->m_highEnoughDifficulty) {
const char* s = share->m_clientCustomUser;
if (share->m_result == SubmittedShare::Result::OK) {
LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(share->m_clientAddrString) << (*s ? ", user " : "") << s << ", effort " << share->m_effort << '%');
share_found = true;
}
else {
static const char* reason_list[] = {
@@ -1117,6 +1149,10 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
client->m_score += share->m_score;
if (share_found) {
++client->m_sidechainShares;
}
if (bad_share && (client->m_score <= BAN_THRESHOLD_POINTS)) {
client->ban(server->m_banTime);
client->close();
@@ -1156,6 +1192,10 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
void StratumServer::on_shutdown()
{
{
MutexLock lock(m_resetShareCountersLock);
uv_close(reinterpret_cast<uv_handle_t*>(&m_resetShareCountersAsync), nullptr);
}
{
MutexLock lock(m_blobsQueueLock);
uv_close(reinterpret_cast<uv_handle_t*>(&m_blobsAsync), nullptr);
@@ -1181,6 +1221,8 @@ StratumServer::StratumClient::StratumClient()
, m_customUser{}
, m_lastJobTarget(0)
, m_score(0)
, m_stratumShares(0)
, m_sidechainShares(0)
{
m_rawReadBuf[0] = '\0';
m_stratumReadBuf[0] = '\0';
@@ -1210,6 +1252,9 @@ void StratumServer::StratumClient::reset()
m_lastJobTarget = 0;
m_score = 0;
m_stratumShares = 0;
m_sidechainShares = 0;
}
bool StratumServer::StratumClient::on_connect()
+10 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -91,6 +91,9 @@ public:
uint64_t m_lastJobTarget;
int32_t m_score;
uint32_t m_stratumShares;
uint32_t m_sidechainShares;
};
[[nodiscard]] bool on_login(StratumClient* client, uint32_t id, const char* login);
@@ -128,6 +131,12 @@ private:
hash m_seedHash;
};
uv_mutex_t m_resetShareCountersLock;
uv_async_t m_resetShareCountersAsync;
static void on_reset_share_counters(uv_async_t* handle) { reinterpret_cast<StratumServer*>(handle->data)->on_reset_share_counters(); }
void on_reset_share_counters();
uv_mutex_t m_blobsQueueLock;
uv_async_t m_blobsAsync;
std::vector<BlobsData*> m_blobsQueue;
+180 -37
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@ static thread_local const char* log_category_prefix = "TCPServer ";
namespace p2pool {
TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy)
TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy, Params::ProxyType socks5ProxyType, bool proxyProtocol)
: m_allocateNewClient(allocate_new_client)
, m_defaultBacklog(default_backlog)
, m_loopThread{}
@@ -32,9 +32,11 @@ TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_
, m_portMapping(0)
#endif
, m_socks5Proxy(socks5Proxy)
, m_socks5ProxyType(socks5ProxyType)
, m_socks5ProxyV6(false)
, m_socks5ProxyIP{}
, m_socks5ProxyPort(-1)
, m_proxyProtocol(proxyProtocol)
, m_finished(0)
, m_listenPort(-1)
, m_loop{}
@@ -319,9 +321,9 @@ bool TCPServer::connect_to_peer(bool is_v6, const raw_ip& ip, int port)
bool TCPServer::connect_to_peer(const std::string& domain, int port)
{
if (m_socks5Proxy.empty()) {
LOGERR(1, "Can't connect to " << domain << ": SOCKS5 proxy is required");
return false;
}
LOGERR(1, "Can't connect to " << domain << ": SOCKS5 proxy is required");
return false;
}
if (m_finished.load()) {
return false;
@@ -337,7 +339,7 @@ bool TCPServer::connect_to_peer(const std::string& domain, int port)
s << domain << ':' << port << '\0';
if (s.m_spilled) {
LOGERR(1, "Can't connect to " << domain << ": too long domain name");
LOGERR(1, "Can't connect to " << domain << ": too long domain name");
return false;
}
@@ -891,45 +893,51 @@ void TCPServer::on_new_client(uv_stream_t* server, Client* client)
LOGINFO(5, "new connection " << (client->m_isIncoming ? "from " : "to ") << log::Gray() << static_cast<char*>(client->m_addrString));
if (is_banned(client->isV6(), client->m_addr)) {
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " is banned, disconnecting");
client->close();
return;
if (m_proxyProtocol && client->m_isIncoming) {
// Defer ban check and on_connect until real IP is extracted from PROXY protocol header
client->m_proxyProtocolState = Client::ProxyProtocolState::ExpectingHeader;
}
TCPServer* owner = client->m_owner;
if (owner->m_finished.load()) {
client->close();
return;
}
if (client->m_isIncoming || owner->m_socks5Proxy.empty()) {
if (!client->on_connect()) {
else {
if (is_banned(client->isV6(), client->m_addr)) {
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " is banned, disconnecting");
client->close();
return;
}
}
else {
const bool result = owner->send(client,
[](uint8_t* buf, size_t buf_size) -> size_t
{
if (buf_size < 3) {
return 0;
}
buf[0] = 5; // Protocol version (SOCKS5)
buf[1] = 1; // NMETHODS
buf[2] = 0; // Method 0 (no authentication)
TCPServer* owner = client->m_owner;
return 3;
});
if (owner->m_finished.load()) {
client->close();
return;
}
if (result) {
client->m_socks5ProxyState = Client::Socks5ProxyState::MethodSelectionSent;
if (client->m_isIncoming || owner->m_socks5Proxy.empty()) {
if (!client->on_connect()) {
client->close();
return;
}
}
else {
client->close();
const bool result = owner->send(client,
[](uint8_t* buf, size_t buf_size) -> size_t
{
if (buf_size < 3) {
return 0;
}
buf[0] = 5; // Protocol version (SOCKS5)
buf[1] = 1; // NMETHODS
buf[2] = 0; // Method 0 (no authentication)
return 3;
});
if (result) {
client->m_socks5ProxyState = Client::Socks5ProxyState::MethodSelectionSent;
}
else {
client->close();
}
}
}
@@ -1084,6 +1092,7 @@ TCPServer::Client::Client(char* read_buf, size_t size)
, m_port(0)
, m_addrString{}
, m_socks5ProxyState(Socks5ProxyState::Default)
, m_proxyProtocolState(ProxyProtocolState::None)
, m_resetCounter{ 0 }
#ifdef WITH_TLS
, m_tlsChecked(false)
@@ -1110,6 +1119,7 @@ void TCPServer::Client::reset()
m_port = -1;
m_addrString[0] = '\0';
m_socks5ProxyState = Socks5ProxyState::Default;
m_proxyProtocolState = ProxyProtocolState::None;
m_readBuf[0] = '\0';
m_readBuf[m_readBufSize - 1] = '\0';
@@ -1154,7 +1164,12 @@ void TCPServer::Client::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf
if (nread > 0) {
if (client->m_owner && !client->m_owner->m_finished.load()) {
if (client->m_socks5ProxyState == Socks5ProxyState::Default) {
if (client->m_proxyProtocolState == ProxyProtocolState::ExpectingHeader) {
if (!client->on_proxy_protocol(buf->base, static_cast<uint32_t>(nread))) {
client->close();
}
}
else if (client->m_socks5ProxyState == Socks5ProxyState::Default) {
if (!client->on_read(buf->base, static_cast<uint32_t>(nread))) {
client->close();
}
@@ -1314,6 +1329,134 @@ bool TCPServer::Client::on_proxy_handshake(const char* data, uint32_t size)
return true;
}
bool TCPServer::Client::on_proxy_protocol(const char* data, uint32_t size)
{
// PROXY protocol v2 signature
static constexpr uint8_t ppv2_signature[12] = { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + m_readBufSize)) {
LOGERR(1, "peer " << static_cast<char*>(m_addrString) << " invalid data pointer or size in on_proxy_protocol()");
return false;
}
m_numRead += size;
// Need at least 16 bytes for the fixed header
if (m_numRead < 16) {
return true;
}
const uint8_t* p = reinterpret_cast<const uint8_t*>(m_readBuf);
// Validate 12-byte signature
if (memcmp(p, ppv2_signature, 12) != 0) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " invalid PROXY protocol v2 signature");
return false;
}
// Byte 12: version (high nibble) and command (low nibble)
const uint8_t ver_cmd = p[12];
const uint8_t version = (ver_cmd >> 4) & 0x0F;
const uint8_t command = ver_cmd & 0x0F;
if (version != 2) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " unsupported PROXY protocol version " << version);
return false;
}
if (command > 1) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " invalid PROXY protocol command " << command);
return false;
}
// Byte 13: address family (high nibble) and protocol (low nibble)
const uint8_t family_proto = p[13];
// Bytes 14-15: address data length (big-endian), includes address block + optional TLV extensions
const uint16_t addr_len = (static_cast<uint16_t>(p[14]) << 8) | static_cast<uint16_t>(p[15]);
const uint32_t total_header_len = 16 + static_cast<uint32_t>(addr_len);
if (total_header_len > m_readBufSize) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " PROXY protocol v2 header too large (" << total_header_len << " bytes)");
return false;
}
// Wait for complete header
if (m_numRead < total_header_len) {
return true;
}
// PROXY command: extract real client address
if (command == 1) {
const uint8_t family = (family_proto >> 4) & 0x0F;
if (family == 1) {
// AF_INET: src(4) + dst(4) + sport(2) + dport(2) = 12 bytes minimum, may be larger with TLV extensions
if (addr_len < 12) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " PROXY protocol v2 IPv4 address data too short (" << addr_len << " bytes)");
return false;
}
memcpy(m_addr.data, raw_ip::ipv4_prefix, sizeof(raw_ip::ipv4_prefix));
memcpy(m_addr.data + sizeof(raw_ip::ipv4_prefix), p + 16, 4);
m_port = (static_cast<int>(p[24]) << 8) | static_cast<int>(p[25]);
m_addressType = AddressType::IPv4;
}
else if (family == 2) {
// AF_INET6: src(16) + dst(16) + sport(2) + dport(2) = 36 bytes minimum, may be larger with TLV extensions
if (addr_len < 36) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " PROXY protocol v2 IPv6 address data too short (" << addr_len << " bytes)");
return false;
}
memcpy(m_addr.data, p + 16, 16);
m_port = (static_cast<int>(p[48]) << 8) | static_cast<int>(p[49]);
m_addressType = AddressType::IPv6;
}
else {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " PROXY protocol v2 unsupported address family " << family);
return false;
}
init_addr_string();
LOGINFO(5, "PROXY protocol v2: real address is " << log::Gray() << static_cast<char*>(m_addrString));
}
// LOCAL command (health checks): keep original address
// Move remaining data to beginning of buffer
m_numRead -= total_header_len;
if (m_numRead > 0) {
memmove(m_readBuf, m_readBuf + total_header_len, m_numRead);
}
m_proxyProtocolState = ProxyProtocolState::HeaderReceived;
// Deferred ban check with real IP
if (m_owner->is_banned(isV6(), m_addr)) {
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(m_addrString) << log::NoColor() << " is banned, disconnecting");
return false;
}
if (m_owner->m_finished.load()) {
return false;
}
if (!on_connect()) {
return false;
}
// Pass remaining data to the protocol handler
if (m_numRead > 0) {
const uint32_t nread = m_numRead;
m_numRead = 0;
if (!on_read(m_readBuf, nread)) {
return false;
}
}
return true;
}
void TCPServer::Client::on_write(uv_write_t* req, int status)
{
WriteBuf* buf = static_cast<WriteBuf*>(req->data);
+13 -2
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
#pragma once
#include "uv_util.h"
#include "params.h"
#ifdef WITH_TLS
#include "tls.h"
@@ -33,7 +34,7 @@ public:
struct Client;
typedef Client* (*allocate_client_callback)();
TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy);
TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy, Params::ProxyType socks5ProxyType, bool proxyProtocol = false);
virtual ~TCPServer();
[[nodiscard]] bool connect_to_peer(bool is_v6, const char* ip, int port);
@@ -66,6 +67,7 @@ public:
[[nodiscard]] virtual bool on_connect() = 0;
[[nodiscard]] virtual bool on_read(const char* data, uint32_t size) = 0;
[[nodiscard]] bool on_proxy_handshake(const char* data, uint32_t size);
[[nodiscard]] bool on_proxy_protocol(const char* data, uint32_t size);
virtual void on_connect_failed(int /*err*/) {}
virtual void on_read_failed(int /*err*/) {}
virtual void on_disconnected() {}
@@ -120,6 +122,12 @@ public:
ConnectRequestSent,
} m_socks5ProxyState;
enum class ProxyProtocolState : uint8_t {
None,
ExpectingHeader,
HeaderReceived,
} m_proxyProtocolState;
std::atomic<uint32_t> m_resetCounter;
#ifdef WITH_TLS
@@ -191,10 +199,13 @@ protected:
#endif
std::string m_socks5Proxy;
Params::ProxyType m_socks5ProxyType;
bool m_socks5ProxyV6;
raw_ip m_socks5ProxyIP;
int m_socks5ProxyPort;
bool m_proxyProtocol;
std::atomic<int> m_finished;
int m_listenPort;
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+2 -6
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1014,12 +1014,8 @@ hash from_onion_v3(const std::string& address)
return {};
}
// Convert address to lowercase
std::string s = address;
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
// Checksum validation
if (to_onion_v3(result) != s) {
if (to_onion_v3(result) != tolower(address)) {
LOGWARN(3, "Invalid onion address \"" << address << "\": checksum failed");
return {};
}
+14 -2
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,7 +35,7 @@
namespace p2pool {
#define P2POOL_VERSION_MAJOR 4
#define P2POOL_VERSION_MINOR 13
#define P2POOL_VERSION_MINOR 14
#define P2POOL_VERSION_PATCH 0
constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;
@@ -395,6 +395,18 @@ FORCEINLINE void secure_zero_memory(T& value)
secure_zero_memory(&value, sizeof(T));
}
FORCEINLINE std::string tolower(const std::string& s)
{
std::string result;
result.reserve(s.size() + 1);
for (char c : s) {
result.push_back(static_cast<char>(std::tolower(c)));
}
return result;
}
std::string to_onion_v3(const hash& pubkey);
hash from_onion_v3(const std::string& address);
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
* Portions Copyright (c) 2012-2013 The Cryptonote developers
* Portions Copyright (c) 2014-2021 The Monero Project
* Portions Copyright (c) 2021 XMRig <https://github.com/xmrig>
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
+11 -4
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,13 @@ ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::s
m_proxy.clear();
}
const bool is_v6 = address.find_first_of(':') != std::string::npos;
if (is_v6) {
m_publisher.set(zmq::sockopt::ipv6, 1);
m_subscriber.set(zmq::sockopt::ipv6, 1);
}
char addr_buf[log::Stream::BUF_SIZE + 1];
addr_buf[0] = '\0';
@@ -49,7 +56,7 @@ ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::s
try {
log::Stream s(addr_buf);
s << "tcp://127.0.0.1:" << port << '\0';
s << (is_v6 ? "tcp://[::1]:" : "tcp://127.0.0.1:") << port << '\0';
m_publisher.bind(addr_buf);
m_publisherPort = static_cast<uint16_t>(port);
break;
@@ -65,11 +72,11 @@ ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::s
throw zmq::error_t(EFSM);
}
LOGINFO(5, "listening on tcp://127.0.0.1:" << m_publisherPort << " for internal communications");
std::string addr(addr_buf);
LOGINFO(5, "listening on " << addr << " for internal communications");
m_subscriber.set(zmq::sockopt::connect_timeout, 1000);
std::string addr(addr_buf);
if (!connect(addr, false)) {
throw zmq::error_t(EFSM);
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2021-2026 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by