Compare commits

...

37 Commits

Author SHA1 Message Date
SChernykh 60285a21dd p2pool v4.8 2025-06-15 09:57:28 +02:00
SChernykh 8f716bd1f1 Merge pull request #363 from Low-power/last-pool-share-found-time-in-local-stratum-api
API: add `last_share_found_time` in `local/stratum`
2025-06-14 12:52:07 +02:00
WHR 009fa0f474 API: add 'last_share_found_time' in local/stratum 2025-06-14 10:26:07 +08:00
SChernykh cea19f1c0d Log: reopen it in the worker thread only
Moved it to the worker thread to contain  it - there is no need to have outside access to its data.
2025-06-12 11:48:55 +02:00
SChernykh 0d0bf9cdee Merge pull request #362 from Low-power/reopen-log-file
Reopening of the log file on SIGUSR1 didn't work as expected
2025-06-11 23:11:32 +02:00
SChernykh c353daeb85 TCPServer: fixed SOCKS5 error checking logic 2025-06-11 20:14:35 +02:00
WHR 865bce5774 Always reopen the log file on SIGUSR1 2025-06-12 00:53:44 +08:00
SChernykh 853b942af7 Console: fixed command length calculation 2025-06-11 16:48:48 +02:00
SChernykh a9d9e1b48a Merge pull request #361 from Low-power/docs-bsd-rc-script
Create document for running P2Pool as a service on FreeBSD
2025-06-11 13:33:23 +02:00
SChernykh 2f06a8b9b8 Fixed build 2025-06-11 12:45:35 +02:00
WHR 197b260d88 Create document for running P2Pool as a service on FreeBSD 2025-06-11 18:38:47 +08:00
SChernykh 26bf2f07a0 Console: don't let random unformatted data end up in the log 2025-06-11 11:49:38 +02:00
SChernykh 09532c901a CMake: removed unused dependencies 2025-06-11 10:22:07 +02:00
SChernykh ab89a3c792 Fixed GCC-8 builds 2025-06-10 22:20:55 +02:00
SChernykh 2fe5dd8a36 Console: don't listen on a TCP port when local API is not enabled 2025-06-10 22:11:26 +02:00
SChernykh 17279708e5 Console: limit access via TCP 2025-06-10 21:51:05 +02:00
SChernykh e577b298b6 CI: fixed MSVC paths 2025-06-10 20:57:01 +02:00
SChernykh d66a2603e3 Merge pull request #360 from Low-power/mebibyte-unit
Correct unit prefix symbol for unit `mebibyte`
2025-06-10 19:30:08 +02:00
SChernykh 8bb317c4b7 CI: added Ubuntu RISC-V build, fixed Windows builds 2025-06-10 19:13:14 +02:00
SChernykh 9ce118ed82 Merge pull request #358 from Low-power/configurable-stratum-ban-time
Make ban time of stratum clients configurable
2025-06-10 18:34:16 +02:00
WHR aa303a96d1 Correct unit prefix symbol for unit 'mebibyte' 2025-06-10 21:16:21 +08:00
WHR 6c4520481b Make ban time of stratum clients configurable via '--stratum-ban-time' option 2025-06-10 20:08:09 +08:00
SChernykh 62707656eb Merge pull request #357 from Low-power/kilohash-per-second-unit
Correct unit prefix symbol for unit `kilohash per second`
2025-06-10 14:06:00 +02:00
WHR 20caceee5d Correct unit prefix symbol for unit 'kilohash per second' 2025-06-10 11:38:25 +08:00
SChernykh 3ac7c0c243 CI: use latest-stable Alpine branch for the RISC-V build 2025-06-09 15:38:37 +02:00
SChernykh ae6a08ee25 Self-test: added more output 2025-06-09 08:35:39 +02:00
SChernykh afa82f4b48 Fixed build 2025-06-08 23:46:10 +02:00
SChernykh e7f87085fb Fixed host ping time calculation when using SOCKS5 proxy 2025-06-08 20:37:55 +02:00
SChernykh 3147a2e968 Fixed build errors 2025-06-06 20:21:47 +02:00
SChernykh 435e6c7599 Tari: added block push via gRPC API 2025-06-06 19:02:08 +02:00
SChernykh ce840733f1 Merge mining: get a new block template immediately after submitting a block. 2025-06-06 12:36:17 +02:00
SChernykh 54d278643d CI: sync test - added merge mining 2025-06-05 23:22:11 +02:00
SChernykh 8d639bfcf2 API: added chain ID to the merge mining data 2025-06-05 11:31:06 +02:00
SChernykh d3026a97b7 API: added merge mining data 2025-06-04 11:46:10 +02:00
SChernykh 77c28df3f0 Updated curl to 8.14.1 2025-06-04 10:09:41 +02:00
SChernykh b06fcc7516 Fix: don't use outdated merge mining data
And warn the user in the log
2025-06-02 14:09:28 +02:00
SChernykh a01ea2d9d8 Updated Monero/P2Pool hardfork info 2025-05-30 14:19:52 +02:00
33 changed files with 821 additions and 141 deletions
+106 -12
View File
@@ -14,14 +14,14 @@ jobs:
build-alpine-static:
timeout-minutes: 240
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
matrix:
config:
- {arch: x86_64, branch: latest-stable, flags: "-ffunction-sections"}
- {arch: aarch64, branch: latest-stable, flags: "-ffunction-sections -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
- {arch: riscv64, branch: edge, flags: "-ffunction-sections"}
- {arch: riscv64, branch: latest-stable, flags: "-ffunction-sections"}
steps:
- name: Setup Alpine Linux
@@ -63,7 +63,7 @@ jobs:
cd external/src/libzmq
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -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
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM="3.5" -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
make -j$(nproc)
- name: Build p2pool
@@ -71,7 +71,7 @@ jobs:
run: |
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_BINARY=ON -DARCH_ID=${{ matrix.config.arch }}
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM="3.5" -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_BINARY=ON -DARCH_ID=${{ matrix.config.arch }}
make -j$(nproc) p2pool
- name: Run RandomX tests
@@ -88,7 +88,7 @@ jobs:
cd tests
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -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=${{ matrix.config.arch }}
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM="3.5" -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=${{ matrix.config.arch }}
make -j$(nproc) p2pool_tests
- name: Run tests
@@ -130,7 +130,7 @@ jobs:
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev ${{ matrix.config.c }} ${{ matrix.config.cpp }}
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev ${{ matrix.config.c }} ${{ matrix.config.cpp }}
- name: Checkout repository
uses: actions/checkout@v4
@@ -260,7 +260,6 @@ jobs:
matrix:
config:
- {os: ubuntu-22.04, flags: "-fuse-linker-plugin -ffunction-sections -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
- {os: ubuntu-24.04, flags: "-fuse-linker-plugin -ffunction-sections -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
steps:
- name: Install dependencies
@@ -330,6 +329,102 @@ 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
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 -DOPENSSL_INCLUDE_DIR=../grpc/third_party/boringssl-with-bazel/src/include
make -j$(nproc)
cd lib && mkdir .libs && cp libcurl.a .libs
- 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
gunzip *.gz
- 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
@@ -423,11 +518,10 @@ jobs:
matrix:
config:
- {vs: Visual Studio 17 2022, os: 2022, vspath: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise", rx: "ON", upnp: "ON", grpc: "ON", tls: "ON"}
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "ON", upnp: "ON", grpc: "ON", tls: "ON"}
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "ON", upnp: "ON", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "OFF", upnp: "ON", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "OFF", upnp: "OFF", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "OFF", upnp: "OFF", grpc: "OFF", tls: "OFF"}
- {vs: Visual Studio 17 2022, os: 2022, vspath: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise", rx: "ON", upnp: "ON", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 17 2022, os: 2022, vspath: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise", rx: "OFF", upnp: "ON", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 17 2022, os: 2022, vspath: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise", rx: "OFF", upnp: "OFF", grpc: "OFF", tls: "ON"}
- {vs: Visual Studio 17 2022, os: 2022, vspath: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise", rx: "OFF", upnp: "OFF", grpc: "OFF", tls: "OFF"}
steps:
- name: Checkout repository
+1 -1
View File
@@ -45,7 +45,7 @@ jobs:
steps:
- name: Install dependencies
run: |
sudo apt update && sudo apt install git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev
sudo apt update && sudo apt install git build-essential cmake libuv1-dev libzmq3-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev
- name: Checkout repository
uses: actions/checkout@v4
+9 -9
View File
@@ -69,7 +69,7 @@ jobs:
python ../tests/src/stratum_dummy.py 2 &
python ../tests/src/stratum_dummy.py 3 &
sudo sysctl vm.mmap_rnd_bits=28
TSAN_OPTIONS="suppressions=../tests/src/tsan_sup.txt halt_on_error=1 history_size=4" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
TSAN_OPTIONS="suppressions=../tests/src/tsan_sup.txt halt_on_error=1 history_size=4" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -155,7 +155,7 @@ jobs:
python ../tests/src/stratum_dummy.py 2 &
python ../tests/src/stratum_dummy.py 3 &
sudo sysctl vm.mmap_rnd_bits=28
MSAN_OPTIONS="halt_on_error=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
MSAN_OPTIONS="halt_on_error=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -180,7 +180,7 @@ jobs:
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
- name: Checkout repository
uses: actions/checkout@v4
@@ -202,7 +202,7 @@ jobs:
python ../tests/src/stratum_dummy.py 2 &
python ../tests/src/stratum_dummy.py 3 &
sudo sysctl vm.mmap_rnd_bits=28
UBSAN_OPTIONS="suppressions=../tests/src/ubsan_sup.txt halt_on_error=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
UBSAN_OPTIONS="suppressions=../tests/src/ubsan_sup.txt halt_on_error=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -227,7 +227,7 @@ jobs:
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
- name: Checkout repository
uses: actions/checkout@v4
@@ -249,7 +249,7 @@ jobs:
python ../tests/src/stratum_dummy.py 2 &
python ../tests/src/stratum_dummy.py 3 &
sudo sysctl vm.mmap_rnd_bits=28
ASAN_OPTIONS="detect_stack_use_after_return=1 atexit=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
ASAN_OPTIONS="detect_stack_use_after_return=1 atexit=1" ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -318,7 +318,7 @@ jobs:
python3 ../tests/src/stratum_dummy.py 1 &
python3 ../tests/src/stratum_dummy.py 2 &
python3 ../tests/src/stratum_dummy.py 3 &
./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -363,7 +363,7 @@ jobs:
start python ../../tests/src/stratum_dummy.py 1
start python ../../tests/src/stratum_dummy.py 2
start python ../../tests/src/stratum_dummy.py 3
p2pool.exe --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
p2pool.exe --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -406,7 +406,7 @@ jobs:
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 1"
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 2"
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 3"
./p2pool.exe --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
./p2pool.exe --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
+8 -16
View File
@@ -256,22 +256,6 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
find_library(CURL_LIBRARY NAMES curl)
endif()
endif()
find_library(SODIUM_LIBRARY sodium)
endif()
find_library(PGM_LIBRARY pgm)
find_library(NORM_LIBRARY norm)
if (PGM_LIBRARY)
set(LIBS ${LIBS} ${PGM_LIBRARY})
endif()
if (NORM_LIBRARY)
set(LIBS ${LIBS} ${NORM_LIBRARY})
endif()
if (SODIUM_LIBRARY)
set(LIBS ${LIBS} ${SODIUM_LIBRARY})
endif()
if(APPLE)
@@ -435,6 +419,10 @@ if (STATIC_BINARY OR STATIC_LIBS)
set(STATIC_LIBS ${STATIC_LIBS} ssl crypto)
endif()
if ((CMAKE_CXX_COMPILER_ID MATCHES GNU) AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9))
set(STATIC_LIBS ${STATIC_LIBS} stdc++fs)
endif()
target_link_libraries(${CMAKE_PROJECT_NAME}
"${CMAKE_SOURCE_DIR}/external/src/libzmq/build/lib/libzmq.a"
"${CMAKE_SOURCE_DIR}/external/src/libuv/build/libuv.a"
@@ -448,6 +436,10 @@ else()
set(LIBS ${LIBS} ssl crypto)
endif()
if ((CMAKE_CXX_COMPILER_ID MATCHES GNU) AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9))
set(LIBS ${LIBS} stdc++fs)
endif()
target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} debug ${CURL_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} optimized ${CURL_LIBRARY} ${LIBS})
endif()
+2 -3
View File
@@ -75,14 +75,13 @@ First you need to find a pool share. This share will stay in [PPLNS](https://en.
## Monero version support
- The latest Monero network upgrade happened on August 13th, 2022 (block 2,688,888).
- The latest P2Pool network upgrade happened on March 18th, 2023 at 21:00 UTC.
- Next P2Pool network upgrade will happen on October 12th, 2024 at 20:00 UTC.
- The latest P2Pool network upgrade happened on October 12th, 2024 at 20:00 UTC.
In order to continue mining on P2Pool, you must update both Monero and P2Pool software to the latest available versions as soon as they are released.
|Monero protocol version|Required Monero software version|Required P2Pool version
|-|-|-|
|v15, v16 (active after August 13th, 2022)|v0.18.0.0 or newer, v0.18.3.4 is recommended|v4.0 or newer
|v15, v16 (active after August 13th, 2022)|v0.18.0.0 or newer, v0.18.4.0 is recommended|v4.0 or newer
## How to mine on P2Pool
+8
View File
@@ -0,0 +1,8 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_PROCESSOR riscv64)
set(CMAKE_C_COMPILER /usr/bin/riscv64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/riscv64-linux-gnu-g++)
set(CMAKE_STRIP /usr/bin/riscv64-linux-gnu-strip)
+93
View File
@@ -0,0 +1,93 @@
## Setting up P2Pool as a service controlled by a RC script (FreeBSD, and possibly other)
In order to use this RC script, it is required to create a `p2pool` user account on the system for this service. An example **passwd(5)** line for this user would be:
```
p2pool:*:818:818::0:0:Monero P2Pool:/var/db/p2pool:/usr/sbin/nologin
```
Also an example **group(5)** line:
```
p2pool:*:818:
```
When creating such an user and a group, make sure the UID and GID aren't being used by any other user/group in the system. The home directory of the user will be used as the data directory of P2Pool; set it to your desired location as needed.
The RC script assumes the P2Pool executable is installed as `/usr/local/bin/p2pool`.
### /usr/local/etc/rc.d/p2pool
```sh
#!/bin/sh
# PROVIDE: p2pool
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown
. /etc/rc.subr
name=p2pool
rcvar=p2pool_enable
load_rc_config $name
: ${p2pool_enable:="NO"} ${p2pool_local_api:="NO"}
[ -z "$p2pool_wallet" ] && exit 1
p2pool_user=p2pool
p2pool_home="`getent passwd ${p2pool_user} | cut -d : -f 6`"
[ -z "$p2pool_home" ] && exit 1
p2pool_env="HOME=$p2pool_home"
p2pool_chdir="$p2pool_home"
procname=/usr/local/bin/p2pool
pidfile="$p2pool_home/p2pool.pid"
command=/usr/sbin/daemon
flags="-p ${pidfile} -f -- ${procname} ${p2pool_flags} --data-dir ${p2pool_home} --wallet ${p2pool_wallet}"
[ -n "${p2pool_api_path}" ] && flags="${flags} --data-api ${p2pool_api_path}"
if checkyesno p2pool_local_api; then
if [ -n "${p2pool_api_path}" ]; then
flags="${flags} --local-api"
else
echo 'Warning: p2pool_local_api="YES" requires p2pool_api_path being set, ignoring' 1>&2
fi
fi
start_precmd="p2pool_prestart"
stop_postcmd="rm -f ${pidfile}"
p2pool_prestart() {
if [ -n "${p2pool_api_path}" ]; then
[ -d "${p2pool_api_path}" ] || mkdir -p "${p2pool_api_path}"
gid="`getent passwd ${p2pool_user} | cut -d : -f 4`"
chown ${p2pool_user}:${gid} "${p2pool_api_path}"
fi
}
run_rc_command "$1"
```
### Configuration variables in /etc/rc.conf (or /etc/rc.conf.local)
* `p2pool_enable` Set to `YES` to enable this service; required.
* `p2pool_wallet` Your wallet address; required.
* `p2pool_api_path` Path to API directory (See p2pool option `--data-api`), this directory will be created automatically if not already exists, on service startup; optional.
* `p2pool_local_api` Set to `YES` to enable creation of `local` path in API directory (See p2pool option `--local-api`), requires `p2pool_api_path` also being set; optional.
* `p2pool_flags` Additional options you want to pass to p2pool; optional.
#### Example
```sh
p2pool_enable="YES"
p2pool_wallet="44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg"
p2pool_api_path="/tmp/p2pool-api"
p2pool_local_api="YES"
p2pool_flags="--host 127.0.0.1 --in-peers 200"
```
## /usr/local/etc/newsyslog.conf.d/p2pool.conf (optional)
You can create this drop-in **newsyslog(8)** configuration file to periodically rotate the P2Pool log file. The drop-in location `/usr/local/etc/newsyslog.conf.d/` assumes that `/etc/newsyslog.conf` contains an `include` directive for searching drop-in configuration files in it.
This example assumes `/var/db/p2pool` as your P2Pool data directory.
```
# log file owner:group mode count size (KiB) when flags pid file signal
/var/db/p2pool/p2pool.log p2pool:p2pool 640 16 65536 @0101T BEJ /var/db/p2pool/p2pool.pid SIGUSR1
```
You should adjust the `count`, `size`, `when` and/or `flags` fields to fit your needs.
+1
View File
@@ -8,6 +8,7 @@
--stratum Comma-separated list of IP:port for stratum server to listen on
--p2p Comma-separated list of IP:port for p2p server to listen on
--addpeers Comma-separated list of IP:port of other p2pool nodes to connect to
--stratum-ban-time N Number of seconds to ban misbehaving stratum client, default is 600
--light-mode Don't allocate RandomX dataset, saves 2GB of RAM
--loglevel Verbosity of the log, integer number between 0 and 6
--data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory
+27
View File
@@ -18,3 +18,30 @@ start_mining **T**|start mining (**T** is the number of threads to use, must be
stop_mining|stop mining
exit|terminate p2pool
version|show p2pool version
### Non-interactive console access
It's possible to send console commands via a local TCP connection. For this, you need to enable the API: `--data-api api --local-api`.
A sample Python script that sends console commands to P2Pool via TCP:
```
import sys
import socket
import json
with open('api/local/console', 'r') as file:
data = json.load(file)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', data['tcp_port']))
command = data['cookie'];
command += sys.argv[1];
command += '\n';
s.sendall(command.encode('utf-8'))
s.close()
```
Run it in P2Pool's directory: `python3 ./p2pool_cmd.py status`
+55 -36
View File
@@ -84,21 +84,30 @@ ConsoleCommands::ConsoleCommands(p2pool* pool)
}
}
std::random_device rd;
std::mt19937_64 rng(rd());
for (int i = 0; i < 10; ++i) {
if (start_listening(false, "127.0.0.1", 49152 + (rng() % 16384))) {
break;
}
}
if (m_listenPort < 0) {
LOGERR(1, "failed to listen on TCP port");
throw std::exception();
}
if (m_pool->api() && m_pool->params().m_localStats) {
std::mt19937_64 rng(RandomDeviceSeed::instance);
// Diffuse the initial state in case it has low quality
rng.discard(10000);
for (int i = 0; i < 10; ++i) {
if (start_listening(false, "127.0.0.1", 49152 + (rng() % 16384))) {
break;
}
}
if (m_listenPort < 0) {
LOGERR(1, "failed to listen on TCP port");
throw std::exception();
}
// 20 random characters in the range [32, 126] should be enough for 128 bits of entropy
m_cookie.resize(20);
for (char& c : m_cookie) {
c = static_cast<char>(rng() % (127 - 32) + 32);
}
m_pool->api()->set(p2pool_api::Category::LOCAL, "console",
[stdin_type, this](log::Stream& s)
{
@@ -114,7 +123,7 @@ ConsoleCommands::ConsoleCommands(p2pool* pool)
s << static_cast<int>(stdin_type);
}
s << "\",\"tcp_port\":" << m_listenPort << '}';
s << "\",\"tcp_port\":" << m_listenPort << ",\"cookie\":\"" << log::EscapedString(m_cookie) << "\"}";
});
}
@@ -349,7 +358,7 @@ void ConsoleCommands::stdinReadCallback(uv_stream_t* stream, ssize_t nread, cons
ConsoleCommands* pThis = static_cast<ConsoleCommands*>(stream->data);
if (nread > 0) {
pThis->process_input(pThis->m_command, buf->base, static_cast<uint32_t>(nread));
pThis->process_input(pThis->m_command, buf->base, static_cast<uint32_t>(nread), false);
}
else if (nread < 0) {
LOGWARN(4, "read error " << uv_err_name(static_cast<int>(nread)));
@@ -359,7 +368,7 @@ void ConsoleCommands::stdinReadCallback(uv_stream_t* stream, ssize_t nread, cons
}
void ConsoleCommands::process_input(std::string& command, const char* data, uint32_t size)
void ConsoleCommands::process_input(std::string& command, const char* data, uint32_t size, bool check_cookie)
{
command.append(data, size);
@@ -370,31 +379,41 @@ void ConsoleCommands::process_input(std::string& command, const char* data, uint
}
command[k] = '\0';
cmd* c = cmds;
for (; c->name.len; ++c) {
if (!strncmp(command.c_str(), c->name.str, c->name.len)) {
const char* args = (c->name.len + 1 <= k) ? (command.c_str() + c->name.len + 1) : "";
if (check_cookie && ((k <= m_cookie.length()) || (memcmp(command.data(), m_cookie.data(), m_cookie.length()) != 0))) {
LOGWARN(4, "cookie check failed, skipping command " << log::MaskNonASCII(command));
}
else {
if (check_cookie) {
command.erase(0, m_cookie.length());
k -= m_cookie.length();
}
// Skip spaces
while ((args[0] == ' ') || (args[0] == '\t')) {
++args;
}
cmd* c = cmds;
for (; c->name.len; ++c) {
if (!strncmp(command.c_str(), c->name.str, c->name.len)) {
const char* args = (c->name.len + 1 <= k) ? (command.c_str() + c->name.len + 1) : "";
// Check if an argument is required
if (strlen(c->arg) && !strlen(args)) {
LOGWARN(0, c->name.str << " requires arguments");
do_help(nullptr, nullptr);
// Skip spaces
while ((args[0] == ' ') || (args[0] == '\t')) {
++args;
}
// Check if an argument is required
if (strlen(c->arg) && !strlen(args)) {
LOGWARN(0, c->name.str << " requires arguments");
do_help(nullptr, nullptr);
break;
}
c->func(m_pool, args);
break;
}
c->func(m_pool, args);
break;
}
}
if (!c->name.len) {
LOGWARN(0, "Unknown command " << command.c_str());
do_help(nullptr, nullptr);
if (!c->name.len) {
LOGWARN(0, "Unknown command " << log::MaskNonASCII(command));
do_help(nullptr, nullptr);
}
}
k = command.find_first_not_of("\r\n", k + 1);
+3 -2
View File
@@ -40,7 +40,7 @@ public:
size_t size() const override { return sizeof(ConsoleClient); }
bool on_connect() override { return true; };
bool on_read(const char* data, uint32_t size) override { static_cast<ConsoleCommands*>(m_owner)->process_input(m_command, data, size); return true; };
bool on_read(const char* data, uint32_t size) override { static_cast<ConsoleCommands*>(m_owner)->process_input(m_command, data, size, true); return true; };
alignas(8) char m_consoleReadBuf[1024] = {};
@@ -62,11 +62,12 @@ private:
bool m_readBufInUse;
std::string m_command;
std::string m_cookie;
static void allocCallback(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
static void stdinReadCallback(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
void process_input(std::string& command, const char* data, uint32_t size);
void process_input(std::string& command, const char* data, uint32_t size, bool check_cookie);
};
} // namespace p2pool
+5 -3
View File
@@ -80,6 +80,8 @@ struct CurlContext
uint64_t m_startTime;
uint64_t m_connectedTime;
std::string m_proxy;
};
CurlContext::CurlContext(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, bool ssl, const std::string& ssl_fingerprint, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop)
@@ -93,6 +95,7 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
, m_headers(nullptr)
, m_startTime(0)
, m_connectedTime(0)
, m_proxy(proxy)
{
m_pollHandles.reserve(2);
@@ -244,9 +247,8 @@ CurlContext::~CurlContext()
double tcp_ping = 0.0;
if (m_error.empty() && !m_response.empty()) {
if (m_connectedTime) {
tcp_ping = static_cast<double>(m_connectedTime - m_startTime) / 1000.0;
}
const uint64_t t = (m_proxy.empty() && m_connectedTime) ? m_connectedTime : microseconds_since_epoch();
tcp_ping = static_cast<double>(t - m_startTime) / 1000.0;
(*m_callback)(m_response.data(), m_response.size(), tcp_ping);
}
delete m_callback;
+61 -11
View File
@@ -24,6 +24,10 @@
#include <stdlib.h>
#include <clocale>
#if defined(_WIN32) && !defined(S_ISREG)
#define S_ISREG(M) (((M) & _S_IFMT) == _S_IFREG)
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
@@ -118,6 +122,7 @@ public:
: m_writePos(0)
, m_readPos(0)
, m_stopped(false)
, m_needReopen(false)
{
#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG)
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
@@ -128,11 +133,6 @@ public:
std::setlocale(LC_ALL, "en_001");
m_logFilePath = DATA_DIR + log_file_name;
m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary);
if (!m_logFile.is_open()) {
fprintf(stderr, "failed to open %s: error %d\n", m_logFilePath.c_str(), errno);
}
m_buf.resize(BUF_SIZE);
@@ -219,6 +219,12 @@ public:
const std::string& log_file_path() const { return m_logFilePath; }
FORCEINLINE void schedule_reopen()
{
m_needReopen = true;
uv_cond_signal(&m_cond);
}
private:
static void init_uv_threadpool()
{
@@ -245,13 +251,41 @@ private:
}
}
bool reopen(struct stat& st)
{
st = {};
if (m_logFile.is_open()) {
m_logFile.close();
}
m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary);
if (!m_logFile.is_open()) {
return false;
}
if (stat(m_logFilePath.c_str(), &st) != 0) {
st = {};
return false;
}
return true;
}
private:
static void run_wrapper(void* arg) { reinterpret_cast<Worker*>(arg)->run(); }
NOINLINE void run()
{
set_thread_name("Logger");
struct stat log_file_st;
if (!reopen(log_file_st)) {
fprintf(stderr, "failed to open %s: error %d\n", m_logFilePath.c_str(), errno);
}
do {
uv_mutex_lock(&m_mutex);
if (m_readPos == m_writePos.load()) {
@@ -264,6 +298,14 @@ private:
}
uv_mutex_unlock(&m_mutex);
bool expected = true;
if (m_needReopen.compare_exchange_strong(expected, false)) {
// Reopen the log file on request (logrotate support)
if(reopen(log_file_st)) {
LOGINFO(0, "reopened " << m_logFilePath);
}
}
for (uint32_t writePos = m_writePos.load(); m_readPos != writePos; writePos = m_writePos.load()) {
// We have at least one log slot pending, possibly more than one
// Process everything in a loop before reading m_writePos again
@@ -327,11 +369,18 @@ private:
if (m_logFile.is_open()) {
m_logFile.flush();
// Reopen the log file if it's been moved (logrotate support)
// Automatically reopen the file if either it
// no longer exists or it is now a different
// regular file; this detects manual moving or
// recreating of the file
struct stat buf;
if (stat(m_logFilePath.c_str(), &buf) != 0) {
m_logFile.close();
m_logFile.open(m_logFilePath, std::ios::app | std::ios::binary);
if (stat(m_logFilePath.c_str(), &buf) == 0) {
if(log_file_st.st_dev && log_file_st.st_ino && S_ISREG(buf.st_mode) &&
(buf.st_dev != log_file_st.st_dev || buf.st_ino != log_file_st.st_ino)) {
reopen(log_file_st);
}
} else if(errno == ENOENT) {
reopen(log_file_st);
}
}
@@ -376,6 +425,7 @@ private:
uv_thread_t m_worker;
bool m_stopped;
std::atomic<bool> m_needReopen;
std::ofstream m_logFile;
std::string m_logFilePath;
@@ -445,7 +495,7 @@ void reopen()
{
// This will trigger the worker thread which will then reopen log file if it's been moved
#ifndef P2POOL_LOG_DISABLE
LOGINFO(0, "reopening " << worker->log_file_path());
worker->schedule_reopen();
#endif
}
+46 -1
View File
@@ -344,7 +344,7 @@ template<> struct log::Stream::Entry<Hashrate>
const double x = static_cast<double>(value.m_data);
static constexpr const char* units[] = { "H/s", "KH/s", "MH/s", "GH/s", "TH/s", "PH/s", "EH/s" };
static constexpr const char* units[] = { "H/s", "kH/s", "MH/s", "GH/s", "TH/s", "PH/s", "EH/s" };
int n;
char buf[32];
@@ -435,6 +435,51 @@ template<> struct log::Stream::Entry<Duration>
}
};
struct EscapedString
{
explicit FORCEINLINE EscapedString(const std::string& data, const char* characters_to_escape = "\"\\", char escape_character = '\\')
{
m_data.reserve(data.length() * 2);
for (const char c : data) {
if (strchr(characters_to_escape, c)) {
m_data.append(1, escape_character);
}
m_data.append(1, c);
}
}
FORCEINLINE operator const std::string&() const { return m_data; }
std::string m_data;
};
template<> struct log::Stream::Entry<EscapedString>
{
static FORCEINLINE void put(const EscapedString& value, Stream* wrapper) { *wrapper << value.m_data; }
};
struct MaskNonASCII
{
explicit FORCEINLINE MaskNonASCII(const std::string& data, char mask_character = '?') : m_data(data)
{
for (char& c : m_data) {
if ((c < 32) || (c >= 127)) {
c = mask_character;
}
}
}
FORCEINLINE operator const std::string&() const { return m_data; }
std::string m_data;
};
template<> struct log::Stream::Entry<MaskNonASCII>
{
static FORCEINLINE void put(const MaskNonASCII& value, Stream* wrapper) { *wrapper << value.m_data; }
};
template<typename T>
struct PadRight
{
+37 -1
View File
@@ -21,6 +21,22 @@
#include "stratum_server.h"
#include "p2p_server.h"
#include <curl/curl.h>
#ifdef WITH_GRPC
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4574)
#endif
#include <grpc/grpc.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // WITH_GRPC
#include <filesystem>
#ifdef WITH_RANDOMX
@@ -46,6 +62,7 @@ void p2pool_usage()
"--stratum Comma-separated list of IP:port for stratum server to listen on\n"
"--p2p Comma-separated list of IP:port for p2p server to listen on\n"
"--addpeers Comma-separated list of IP:port of other p2pool nodes to connect to\n"
"--stratum-ban-time N Number of seconds to ban misbehaving stratum client, default is %u\n"
"--light-mode Don't allocate RandomX dataset, saves 2GB of RAM\n"
"--loglevel Verbosity of the log, integer number between 0 and %d\n"
"--data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory\n"
@@ -86,6 +103,7 @@ void p2pool_usage()
"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",
p2pool::VERSION,
static_cast<uint32_t>(p2pool::DEFAULT_STRATUM_BAN_TIME),
p2pool::log::MAX_GLOBAL_LOG_LEVEL,
p2pool::DEFAULT_P2P_PORT,
p2pool::DEFAULT_P2P_PORT_MINI,
@@ -108,6 +126,8 @@ void p2pool_version()
int p2pool_test()
{
printf("Self-test started\n");
#ifdef WITH_RANDOMX
const char myKey[] = "test key 000";
const char myInput[] = "This is a test";
@@ -122,7 +142,10 @@ int p2pool_test()
return 1;
}
}
printf("RandomX cache allocated\n");
randomx_init_cache(myCache, myKey, sizeof(myKey) - 1);
printf("RandomX cache initialized\n");
randomx_dataset* myDataset = randomx_alloc_dataset(flags | RANDOMX_FLAG_LARGE_PAGES);
if (!myDataset) {
@@ -132,6 +155,7 @@ int p2pool_test()
return 1;
}
}
printf("RandomX dataset allocated\n");
{
const uint32_t numThreads = std::max(std::thread::hardware_concurrency(), 1U);
@@ -152,6 +176,7 @@ int p2pool_test()
t.join();
}
}
printf("RandomX dataset initialized\n");
randomx_release_cache(myCache);
@@ -163,12 +188,15 @@ int p2pool_test()
return 1;
}
}
printf("RandomX VM created\n");
memset(hash, 0, sizeof(hash));
memcpy(hash, myInput, sizeof(myInput));
for (size_t i = 0; i < 100; ++i) {
for (int i = 0; i < 100; ++i) {
printf("RandomX: calculating hash %d...", i);
randomx_calculate_hash(myMachine, &hash, sizeof(hash), hash);
printf("done\n");
}
char buf[RANDOMX_HASH_SIZE * 2 + 1] = {};
@@ -251,6 +279,10 @@ int main(int argc, char* argv[])
return result;
}
#ifdef WITH_GRPC
grpc_init();
#endif
try {
p2pool::p2pool pool(argc, argv);
result = pool.run();
@@ -259,6 +291,10 @@ int main(int argc, char* argv[])
result = 1;
}
#ifdef WITH_GRPC
grpc_shutdown();
#endif
curl_global_cleanup();
p2pool::destroy_crypto_cache();
+33 -7
View File
@@ -48,8 +48,10 @@ struct TrackedAllocation
FORCEINLINE bool operator<(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) < 0; }
FORCEINLINE bool operator==(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) == 0; }
void print(HANDLE h) const
void print(HANDLE h, bool& is_grpc) const
{
is_grpc = false;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {};
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
@@ -66,13 +68,21 @@ struct TrackedAllocation
if (SymFromAddr(h, address, &t1, pSymbol) && SymGetLineFromAddr64(h, address, &t2, &line)) {
const char* s = line.FileName;
const char* file_name = nullptr;
while (*s) {
if ((*s == '\\') || (*s == '/')) {
file_name = s + 1;
}
++s;
}
printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, pSymbol->Name, line.LineNumber);
s = pSymbol->Name;
printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, s, line.LineNumber);
if (!is_grpc && ((strstr(s, "grpc::") == s) || (strstr(s, "grpc_core::") == s) || (strstr(s, "grpc_init") == s))) {
is_grpc = true;
}
}
}
printf("\n");
@@ -130,7 +140,8 @@ void show_top_10_allocations()
for (TrackedAllocation* p = buf; (p < buf + 10) && (p < end); ++p) {
printf("%I64u bytes allocated at:\n", p->allocated_size);
p->print(h);
bool is_grpc;
p->print(h, is_grpc);
}
}
@@ -314,21 +325,36 @@ bool memory_tracking_stop()
const HANDLE h = GetCurrentProcess();
uint64_t total_leaks = 0;
uint64_t grpc_leaks = 0;
for (uint32_t i = 0; i < N; ++i) {
const TrackedAllocation& t = allocations[i];
if (t.allocated_size) {
total_leaks += t.allocated_size;
printf("Memory leak detected, %I64u bytes allocated at %p by thread %u:\n", t.allocated_size, t.p, t.thread_id);
t.print(h);
bool is_grpc;
t.print(h, is_grpc);
if (is_grpc) {
printf("^^^ grpc leak ^^^\n\n");
grpc_leaks += t.allocated_size;
}
else {
printf("^^^ non-grpc leak ^^^\n\n");
total_leaks += t.allocated_size;
}
}
}
if (total_leaks > 0) {
printf("%I64u bytes leaked\n\n", total_leaks);
}
else {
if (grpc_leaks > 0) {
printf("%I64u bytes leaked by gRPC\n\n", grpc_leaks);
}
if ((total_leaks == 0) && (grpc_leaks == 0)) {
printf("No memory leaks detected\n\n");
}
+8
View File
@@ -28,10 +28,17 @@ class IMergeMiningClient
public:
struct ChainParameters
{
ChainParameters() : last_updated(0) {}
enum {
EXPIRE_TIME = 1800,
};
hash aux_id;
hash aux_hash;
std::vector<uint8_t> aux_blob;
difficulty_type aux_diff;
uint64_t last_updated;
};
public:
@@ -43,6 +50,7 @@ public:
virtual void submit_solution(const std::vector<uint8_t>& coinbase_merkle_proof, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) = 0;
virtual void print_status() const = 0;
virtual void api_status(log::Stream&) const = 0;
};
} // namespace p2pool
+29 -6
View File
@@ -31,6 +31,7 @@ namespace p2pool {
MergeMiningClientJSON_RPC::MergeMiningClientJSON_RPC(p2pool* pool, const std::string& host, const std::string& wallet)
: m_host(host)
, m_port(80)
, m_chainParamsTimestamp(0)
, m_auxWallet(wallet)
, m_ping(0.0)
, m_pool(pool)
@@ -281,6 +282,9 @@ bool MergeMiningClientJSON_RPC::parse_merge_mining_get_aux_block(const char* dat
m_chainParams.aux_hash = h;
m_chainParams.aux_diff.lo = result["aux_diff"].GetUint64();
m_chainParams.aux_diff.hi = 0;
m_chainParams.last_updated = seconds_since_epoch();
m_chainParamsTimestamp = time(nullptr);
changed = true;
@@ -318,6 +322,8 @@ void MergeMiningClientJSON_RPC::submit_solution(const std::vector<uint8_t>& /*co
if (size > 0) {
LOGERR(3, "couldn't submit merge mining solution to " << m_host << ':' << m_port << ", error " << log::const_buf(data, size));
}
// Get new mining job
on_timer();
}, &m_loop);
}
@@ -332,19 +338,40 @@ void MergeMiningClientJSON_RPC::print_status() const
);
}
bool MergeMiningClientJSON_RPC::get_params(ChainParameters& out_params) const
void MergeMiningClientJSON_RPC::api_status(log::Stream& s) const
{
ReadLock lock(m_lock);
s << '{'
<< "\"api\":\"JSON RPC\","
<< "\"id\":\"" << m_chainParams.aux_id << "\","
<< "\"host\":\"" << m_host << ':' << m_port << "\","
<< "\"wallet\":\"" << m_auxWallet << "\","
<< "\"difficulty\":" << m_chainParams.aux_diff << ","
<< "\"timestamp\":" << m_chainParamsTimestamp
<< '}';
}
bool MergeMiningClientJSON_RPC::get_params(ChainParameters& out_params) const
{
const uint64_t t = seconds_since_epoch();
ReadLock lock(m_lock);
if (m_chainParams.aux_id.empty() || m_chainParams.aux_diff.empty()) {
return false;
}
if (t >= m_chainParams.last_updated + ChainParameters::EXPIRE_TIME) {
LOGWARN(4, m_host << ':' << m_port << " merge mining data is outdated (" << (t - m_chainParams.last_updated) << " seconds old)");
return false;
}
out_params = m_chainParams;
return true;
}
bool MergeMiningClientJSON_RPC::parse_merge_mining_submit_solution(const char* data, size_t size)
bool MergeMiningClientJSON_RPC::parse_merge_mining_submit_solution(const char* data, size_t size) const
{
auto err = [this](const char* msg) {
LOGWARN(3, "merge_mining_submit_solution to " << m_host << ':' << m_port << " failed: " << msg);
@@ -393,10 +420,6 @@ bool MergeMiningClientJSON_RPC::parse_merge_mining_submit_solution(const char* d
}
LOGINFO(0, log::LightGreen() << "merge_mining_submit_solution to " << m_host << ':' << m_port << ": " << status);
// Get new mining job
on_timer();
return true;
}
+4 -1
View File
@@ -35,6 +35,7 @@ public:
void submit_solution(const std::vector<uint8_t>& coinbase_merkle_proof, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) override;
void print_status() const override;
void api_status(log::Stream&) const override;
private:
static void loop(void* data);
@@ -48,7 +49,7 @@ private:
void merge_mining_get_aux_block(uint64_t height, const hash& prev_id, const std::string& wallet);
bool parse_merge_mining_get_aux_block(const char* data, size_t size, bool& changed);
bool parse_merge_mining_submit_solution(const char* data, size_t size);
bool parse_merge_mining_submit_solution(const char* data, size_t size) const;
std::string m_host;
uint32_t m_port;
@@ -56,6 +57,8 @@ private:
mutable uv_rwlock_t m_lock;
ChainParameters m_chainParams;
uint64_t m_chainParamsTimestamp;
std::string m_auxWallet;
double m_ping;
+178 -13
View File
@@ -25,6 +25,7 @@
#include "pool_block.h"
#include "merkle.h"
#include "side_chain.h"
#include <fstream>
LOG_CATEGORY(MergeMiningClientTari)
@@ -34,6 +35,7 @@ namespace p2pool {
MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, const std::string& wallet)
: m_chainParams{}
, m_chainParamsTimestamp(0)
, m_previousAuxHashes{}
, m_previousAuxHashesIndex(0)
, m_auxWallet(wallet)
@@ -42,6 +44,7 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
, m_server(new TariServer(pool->params().m_socks5Proxy))
, m_hostStr(host)
, m_workerStop(0)
, m_pushBlockStop(0)
{
if (host.find(TARI_PREFIX) != 0) {
LOGERR(1, "Invalid host " << host << " - \"" << TARI_PREFIX << "\" prefix not found");
@@ -84,26 +87,54 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
log::Stream s(buf);
s << "127.0.0.1:" << m_server->external_listen_port();
grpc::ChannelArguments cArgs;
m_channelArgs.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 1000);
cArgs.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 1000);
cArgs.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 1000);
cArgs.SetInt(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 10000);
m_channelArgs.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 1000);
m_channelArgs.SetInt(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 10000);
cArgs.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, -1);
cArgs.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, -1);
m_channelArgs.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, -1);
m_channelArgs.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, -1);
m_TariNode = new BaseNode::Stub(grpc::CreateCustomChannel(buf, grpc::InsecureChannelCredentials(), cArgs));
m_TariNode = new BaseNode::Stub(grpc::CreateCustomChannel(buf, grpc::InsecureChannelCredentials(), m_channelArgs));
uv_mutex_init_checked(&m_workerLock);
uv_cond_init_checked(&m_workerCond);
const int err = uv_thread_create(&m_worker, run_wrapper, this);
int err = uv_thread_create(&m_worker, run_wrapper, this);
if (err) {
LOGERR(1, "failed to start worker thread, error " << uv_err_name(err));
throw std::exception();
}
uv_mutex_init_checked(&m_pushBlockLock);
uv_cond_init_checked(&m_pushBlockCond);
std::ifstream f("tari_nodes.txt");
if (f.is_open()) {
while (f.good()) {
std::string node;
std::getline(f, node);
if (!node.empty()) {
PushBlockThreadData* data = new PushBlockThreadData{ {}, this, std::move(node) };
err = uv_thread_create(&data->m_worker, push_block_thread, data);
if (err) {
LOGERR(1, "failed to start block pusher thread for node " << data->m_node << ", error " << uv_err_name(err));
delete data;
}
else {
m_pushBlockThreads.push_back(data);
// Limit to 16 nodes. More will be just an overkill and a waste of bandwidth.
if (m_pushBlockThreads.size() >= 16) {
break;
}
}
}
}
}
}
MergeMiningClientTari::~MergeMiningClientTari()
@@ -117,6 +148,20 @@ MergeMiningClientTari::~MergeMiningClientTari()
}
uv_thread_join(&m_worker);
if (!m_pushBlockThreads.empty()) {
m_pushBlockStop.exchange(1);
{
MutexLock lock(m_pushBlockLock);
uv_cond_broadcast(&m_pushBlockCond);
}
for (PushBlockThreadData* data : m_pushBlockThreads) {
uv_thread_join(&data->m_worker);
delete data;
}
m_pushBlockThreads.clear();
}
m_server->shutdown_tcp();
delete m_server;
@@ -127,17 +172,27 @@ MergeMiningClientTari::~MergeMiningClientTari()
uv_mutex_destroy(&m_workerLock);
uv_cond_destroy(&m_workerCond);
uv_mutex_destroy(&m_pushBlockLock);
uv_cond_destroy(&m_pushBlockCond);
LOGINFO(1, "stopped");
}
bool MergeMiningClientTari::get_params(ChainParameters& out_params) const
{
const uint64_t t = seconds_since_epoch();
ReadLock lock(m_chainParamsLock);
if (m_chainParams.aux_id.empty() || m_chainParams.aux_diff.empty()) {
return false;
}
if (t >= m_chainParams.last_updated + ChainParameters::EXPIRE_TIME) {
LOGWARN(4, m_hostStr << " merge mining data is outdated (" << (t - m_chainParams.last_updated) << " seconds old)");
return false;
}
out_params = m_chainParams;
return true;
}
@@ -439,6 +494,18 @@ void MergeMiningClientTari::submit_solution(const std::vector<uint8_t>& coinbase
pow->set_pow_data(data);
}
{
const std::string& h = block.header().hash();
LOGINFO(4, "Block " << log::hex_buf(h.data(), h.size()) << ": PoW data is set, everything is ready. Submitting it!");
}
if (!m_pushBlockThreads.empty()) {
MutexLock lock(m_pushBlockLock);
m_blockToPush = block;
uv_cond_broadcast(&m_pushBlockCond);
}
struct Work
{
uv_work_t req;
@@ -464,6 +531,10 @@ void MergeMiningClientTari::submit_solution(const std::vector<uint8_t>& coinbase
const std::string& h = response.block_hash();
LOGINFO(0, log::LightGreen() << "Mined Tari block " << log::hex_buf(h.data(), h.size()) << " at height " << block.header().height());
}
// We've just submitted a new block. Signal the polling thread to stop waiting and get a new block template.
MutexLock lock(client->m_workerLock);
uv_cond_signal(&client->m_workerCond);
}
} *work = new Work(this, std::move(block));
@@ -533,6 +604,23 @@ void MergeMiningClientTari::print_status() const
);
}
void MergeMiningClientTari::api_status(log::Stream& s) const
{
ReadLock lock(m_chainParamsLock);
s << '{'
<< "\"api\":\"Tari gRPC\","
<< "\"id\":\"" << m_chainParams.aux_id << "\","
<< "\"host\":\"" << m_hostStr << "\","
<< "\"wallet\":\"" << m_auxWallet << "\","
<< "\"height\":" << m_tariJobParams.height << ","
<< "\"difficulty\":" << m_tariJobParams.diff << ","
<< "\"reward\":" << m_tariJobParams.reward << ","
<< "\"fees\":" << m_tariJobParams.fees << ","
<< "\"timestamp\":" << m_chainParamsTimestamp
<< '}';
}
void MergeMiningClientTari::run_wrapper(void* arg)
{
reinterpret_cast<MergeMiningClientTari*>(arg)->run();
@@ -560,7 +648,7 @@ void MergeMiningClientTari::run()
(a.failed_checkpoints() == b.failed_checkpoints());
};
for (;;) {
while (!m_workerStop) {
const auto start_time = high_resolution_clock::now();
// Force frequent enough updates (at least every 30 seconds)
@@ -659,8 +747,11 @@ void MergeMiningClientTari::run()
std::copy(mm_hash.begin(), mm_hash.end(), m_chainParams.aux_hash.h);
m_chainParams.aux_diff = static_cast<difficulty_type>(response.miner_data().target_difficulty());
m_chainParams.last_updated = seconds_since_epoch();
m_tariBlock = response.block();
m_chainParamsTimestamp = time(nullptr);
m_tariBlock = std::move(*response.mutable_block());
LOGINFO(4, "Tari aux block template: height = " << job_params.height
<< ", diff = " << job_params.diff
@@ -684,8 +775,8 @@ void MergeMiningClientTari::run()
const int64_t timeout = std::max<int64_t>(500'000'000 - dt, 1'000'000);
if ((m_workerStop.load() != 0) || (uv_cond_timedwait(&m_workerCond, &m_workerLock, timeout) != UV_ETIMEDOUT)) {
return;
if (!m_workerStop) {
uv_cond_timedwait(&m_workerCond, &m_workerLock, timeout);
}
}
}
@@ -855,4 +946,78 @@ bool MergeMiningClientTari::TariClient::on_read(const char* data, uint32_t size)
});
}
void MergeMiningClientTari::push_block_thread(void* arg)
{
set_thread_name("Push Tari block");
PushBlockThreadData* data = reinterpret_cast<PushBlockThreadData*>(arg);
LOGINFO(1, "push block thread ready for " << data->m_node);
try {
data->m_client->push_blocks_to(data->m_node);
}
catch (const std::exception& e) {
LOGERR(0, "Exception in push_blocks_to(" << data->m_node << "): " << e.what());
}
LOGINFO(1, "push block thread stopped for " << data->m_node);
}
void MergeMiningClientTari::push_blocks_to(const std::string& node_address)
{
using namespace tari::rpc;
std::unique_ptr<BaseNode::Stub> node(new BaseNode::Stub(grpc::CreateCustomChannel(node_address, grpc::InsecureChannelCredentials(), m_channelArgs)));
grpc::ClientContext get_tip_info_ctx{};
Empty get_tip_info_request{};
TipInfoResponse tip_info{};
const grpc::Status get_tip_info_status = node->GetTipInfo(&get_tip_info_ctx, get_tip_info_request, &tip_info);
if (!get_tip_info_status.ok()) {
LOGWARN(4, "GetTipInfo failed for " << node_address << ": " << get_tip_info_status.error_message());
if (!get_tip_info_status.error_details().empty()) {
LOGWARN(4, "GetTipInfo failed for " << node_address << ": " << get_tip_info_status.error_details());
}
}
else {
LOGINFO(4, node_address << " is at block height " << tip_info.metadata().best_block_height());
}
while (!m_pushBlockStop) {
Block block;
{
MutexLock lock(m_pushBlockLock);
uv_cond_wait(&m_pushBlockCond, &m_pushBlockLock);
if (m_pushBlockStop) {
return;
}
block = m_blockToPush;
}
const std::string& h = block.header().hash();
LOGINFO(4, "Pushing block " << log::hex_buf(h.data(), h.size()) << " to " << node_address);
grpc::ClientContext ctx;
SubmitBlockResponse response;
const grpc::Status status = node->SubmitBlock(&ctx, block, &response);
if (!status.ok()) {
LOGWARN(4, "SubmitBlock failed for " << node_address << ": " << status.error_message());
if (!status.error_details().empty()) {
LOGWARN(4, "SubmitBlock failed for " << node_address << ": " << status.error_details());
}
}
else {
const std::string& h1 = response.block_hash();
LOGINFO(0, log::LightGreen() << "Pushed Tari block " << log::hex_buf(h1.data(), h1.size()) << " to " << node_address);
}
}
}
} // namespace p2pool
+22
View File
@@ -38,11 +38,14 @@ public:
void submit_solution(const std::vector<uint8_t>& coinbase_merkle_proof, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) override;
void print_status() const override;
void api_status(log::Stream&) const override;
private:
mutable uv_rwlock_t m_chainParamsLock;
ChainParameters m_chainParams;
uint64_t m_chainParamsTimestamp;
enum {
NUM_PREVIOUS_HASHES = 8,
};
@@ -96,6 +99,7 @@ private:
const std::string m_hostStr;
grpc::ChannelArguments m_channelArgs;
tari::rpc::BaseNode::Stub* m_TariNode;
struct TariClient : public TCPServer::Client
@@ -127,6 +131,24 @@ private:
static void run_wrapper(void* arg);
void run();
uv_mutex_t m_pushBlockLock;
uv_cond_t m_pushBlockCond;
std::atomic<uint32_t> m_pushBlockStop;
tari::rpc::Block m_blockToPush;
struct PushBlockThreadData
{
uv_thread_t m_worker;
MergeMiningClientTari* m_client;
std::string m_node;
};
std::vector<PushBlockThreadData*> m_pushBlockThreads;
static void push_block_thread(void* arg);
void push_blocks_to(const std::string& node_address);
};
} // namespace p2pool
+27 -1
View File
@@ -669,7 +669,7 @@ void p2pool::update_aux_data(const hash& chain_id)
aux_id.emplace_back(c.aux_id);
}
}
else {
else if (mm_donation_params_last_updated) {
LOGINFO(5, "update_aux_data: merge mining donation data is stale, not using it");
}
#endif
@@ -716,6 +716,8 @@ void p2pool::update_aux_data(const hash& chain_id)
#if defined(WITH_MERGE_MINING_DONATION) && defined(WITH_TLS)
send_aux_job_donation();
#endif
api_update_aux_data();
}
}
@@ -2024,6 +2026,30 @@ void p2pool::on_external_block(const PoolBlock& block)
}
}
void p2pool::api_update_aux_data()
{
if (!m_api || !m_params->m_localStats || m_stopped) {
return;
}
m_api->set(p2pool_api::Category::LOCAL, "merge_mining",
[this](log::Stream& s)
{
s << "{\"chains\":[";
{
ReadLock lock(m_mergeMiningClientsLock);
for (size_t i = 0, n = m_mergeMiningClients.size(); i < n; ++i) {
if (i > 0) {
s << ',';
}
m_mergeMiningClients[i]->api_status(s);
}
}
s << "]}";
});
}
bool p2pool::get_difficulty_at_height(uint64_t height, difficulty_type& diff)
{
ReadLock lock(m_mainchainLock);
+2
View File
@@ -123,6 +123,8 @@ public:
void api_update_block_found(const ChainMain* data, const PoolBlock* block, bool update_stats_mod = true);
void on_external_block(const PoolBlock& block);
void api_update_aux_data();
bool get_difficulty_at_height(uint64_t height, difficulty_type& diff);
#ifdef WITH_RANDOMX
+11 -6
View File
@@ -64,11 +64,11 @@ p2pool_api::p2pool_api(const std::string& api_path, const bool local_stats)
m_poolPath = m_apiPath + "pool/";
m_localPath = m_apiPath + "local/";
create_dir(m_networkPath);
create_dir(m_poolPath);
create_dir(m_networkPath, false);
create_dir(m_poolPath, false);
if (local_stats) {
create_dir(m_localPath);
create_dir(m_localPath, true);
}
}
@@ -77,14 +77,16 @@ p2pool_api::~p2pool_api()
uv_mutex_destroy(&m_dumpDataLock);
}
void p2pool_api::create_dir(const std::string& path)
void p2pool_api::create_dir(const std::string& path, bool is_restricted)
{
(void) is_restricted;
#ifdef _MSC_VER
int result = _mkdir(path.c_str());
#else
int result = mkdir(path.c_str()
#ifndef _WIN32
, 0775
, is_restricted ? 0750 : 0775
#endif
);
#endif
@@ -169,7 +171,10 @@ void p2pool_api::dump_to_file()
#endif
;
const int result = uv_fs_open(uv_default_loop_checked(), &work->req, work->tmp_name.c_str(), flags, 0644, on_fs_open);
// LOCAL category has restricted access
const int mode = (work->tmp_name.find(m_localPath) == 0) ? 0640 : 0644;
const int result = uv_fs_open(uv_default_loop_checked(), &work->req, work->tmp_name.c_str(), flags, mode, on_fs_open);
if (result < 0) {
LOGWARN(4, "failed to open " << work->tmp_name << ", error " << uv_err_name(result));
delete work;
+1 -1
View File
@@ -41,7 +41,7 @@ public:
void set(Category category, const char* filename, T&& callback) { dump_to_file_async_internal(category, filename, Callback<void, log::Stream&>::Derived<T>(std::move(callback))); }
private:
void create_dir(const std::string& path);
void create_dir(const std::string& path, bool is_restricted);
static void on_dump_to_file(uv_async_t* async) { reinterpret_cast<p2pool_api*>(async->data)->dump_to_file(); }
+16
View File
@@ -26,6 +26,9 @@ void p2pool_usage();
namespace p2pool {
static constexpr uint64_t MIN_STRATUM_BAN_TIME = UINT64_C(1);
static constexpr uint64_t MAX_STRATUM_BAN_TIME = (UINT64_C(1) << 34) - 1;
Params::Params(int argc, char* const argv[])
{
for (int i = 1; i < argc; ++i) {
@@ -79,6 +82,11 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if ((strcmp(argv[i], "--stratum-ban-time") == 0) && (i + 1 < argc)) {
m_stratumBanTime = strtoull(argv[++i], nullptr, 10);
ok = true;
}
if ((strcmp(argv[i], "--p2p") == 0) && (i + 1 < argc)) {
m_p2pAddresses = argv[++i];
ok = true;
@@ -284,6 +292,14 @@ Params::Params(int argc, char* const argv[])
m_stratumAddresses = buf;
}
if(m_stratumBanTime < MIN_STRATUM_BAN_TIME) {
LOGWARN(1, "Value for --stratum-ban-time is too low, adjusting to " << MIN_STRATUM_BAN_TIME);
m_stratumBanTime = MIN_STRATUM_BAN_TIME;
} else if(m_stratumBanTime > MAX_STRATUM_BAN_TIME) {
LOGWARN(1, "Value for --stratum-ban-time is too high, adjusting to " << MAX_STRATUM_BAN_TIME);
m_stratumBanTime = MAX_STRATUM_BAN_TIME;
}
}
bool Params::valid() const
+3
View File
@@ -21,6 +21,8 @@
namespace p2pool {
static constexpr uint64_t DEFAULT_STRATUM_BAN_TIME = 600;
struct Params
{
Params(int argc, char* const argv[]);
@@ -74,6 +76,7 @@ struct Params
std::string m_p2pPeerList;
std::string m_sidechainConfig;
std::string m_apiPath;
uint64_t m_stratumBanTime = DEFAULT_STRATUM_BAN_TIME;
bool m_localStats = false;
bool m_blockCache = true;
#ifdef WITH_RANDOMX
+1 -1
View File
@@ -84,7 +84,7 @@ RandomX_Hasher::RandomX_Hasher(p2pool* pool)
memory_allocated = (memory_allocated + (1 << 20) - 1) >> 20;
LOGINFO(1, "allocated " << memory_allocated << " MB");
LOGINFO(1, "allocated " << memory_allocated << " MiB");
}
RandomX_Hasher::~RandomX_Hasher()
+17 -6
View File
@@ -29,7 +29,6 @@
LOG_CATEGORY(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;
@@ -58,6 +57,7 @@ StratumServer::StratumServer(p2pool* pool)
, m_cumulativeFoundSharesDiff(0.0)
, m_totalFoundSidechainShares(0)
, m_totalFailedSidechainShares(0)
, m_lastSidechainShareFoundTime(0)
, m_totalStratumShares(0)
, m_apiLastUpdateTime(0)
{
@@ -84,6 +84,7 @@ StratumServer::StratumServer(p2pool* pool)
m_showWorkersAsync.data = this;
const Params& params = pool->params();
m_banTime = params.m_stratumBanTime;
start_listening(params.m_stratumAddresses, params.m_upnp && params.m_upnpStratum);
}
@@ -601,6 +602,7 @@ void StratumServer::reset_share_counters()
m_cumulativeHashesAtLastShare = m_cumulativeHashes;
m_totalFoundSidechainShares = 0;
m_totalFailedSidechainShares = 0;
m_lastSidechainShareFoundTime = 0;
}
bool StratumServer::http_enabled() const
@@ -791,7 +793,7 @@ void StratumServer::on_blobs_ready()
// Not logged in yet, on_login() will send the job to this client. Also close inactive connections.
if (cur_time >= client->m_connectedTime + 10) {
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " didn't send login data");
client->ban(DEFAULT_BAN_TIME);
client->ban(m_banTime);
client->close();
}
continue;
@@ -1005,6 +1007,8 @@ void StratumServer::on_share_found(uv_work_t* req)
share->m_score = GOOD_SHARE_POINTS;
const double diff = sidechain_difficulty.to_double();
time_t prev_time;
const time_t cur_time = time(nullptr);
{
WriteLock lock(server->m_hashrateDataLock);
@@ -1014,6 +1018,9 @@ void StratumServer::on_share_found(uv_work_t* req)
server->m_cumulativeFoundSharesDiff += diff;
++server->m_totalFoundSidechainShares;
prev_time = server->m_lastSidechainShareFoundTime;
server->m_lastSidechainShareFoundTime = cur_time;
}
if (!pool->submit_sidechain_block(share->m_templateId, share->m_nonce, share->m_extraNonce)) {
@@ -1022,6 +1029,7 @@ void StratumServer::on_share_found(uv_work_t* req)
if (server->m_totalFoundSidechainShares > 0) {
--server->m_totalFoundSidechainShares;
++server->m_totalFailedSidechainShares;
server->m_lastSidechainShareFoundTime = prev_time;
}
}
}
@@ -1106,7 +1114,7 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
client->m_score += share->m_score;
if (bad_share && (client->m_score <= BAN_THRESHOLD_POINTS)) {
client->ban(DEFAULT_BAN_TIME);
client->ban(server->m_banTime);
client->close();
}
else if (!result) {
@@ -1114,7 +1122,7 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
}
}
else if (bad_share) {
server->ban(share->m_clientIPv6, share->m_clientAddr, DEFAULT_BAN_TIME);
server->ban(share->m_clientIPv6, share->m_clientAddr, server->m_banTime);
}
if (share->m_allocated) {
@@ -1224,7 +1232,7 @@ bool StratumServer::StratumClient::on_read(const char* data, uint32_t size)
auto on_parse = [this](const char* data, uint32_t size) {
if (static_cast<size_t>(m_stratumReadBufBytes) + size > STRATUM_BUF_SIZE) {
LOGWARN(4, "client " << static_cast<const char*>(m_addrString) << " sent too long Stratum message");
ban(DEFAULT_BAN_TIME);
ban(static_cast<StratumServer*>(m_owner)->m_banTime);
return false;
}
@@ -1252,7 +1260,7 @@ bool StratumServer::StratumClient::on_read(const char* data, uint32_t size)
*c = '\0';
if (!process_request(line_start, static_cast<uint32_t>(c - line_start))) {
ban(DEFAULT_BAN_TIME);
ban(static_cast<StratumServer*>(m_owner)->m_banTime);
return false;
}
@@ -1494,6 +1502,7 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
uint64_t hashes_since_last_share;
double average_effort;
uint32_t shares_found, shares_failed;
time_t last_share_found_time;
uint64_t total_stratum_shares;
{
@@ -1525,6 +1534,7 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
shares_found = m_totalFoundSidechainShares;
shares_failed = m_totalFailedSidechainShares;
last_share_found_time = m_lastSidechainShareFoundTime;
total_stratum_shares = m_totalStratumShares;
}
@@ -1546,6 +1556,7 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
<< ",\"hashrate_24h\":" << hashrate_24h
<< ",\"total_hashes\":" << total_hashes
<< ",\"total_stratum_shares\":" << total_stratum_shares
<< ",\"last_share_found_time\":" << last_share_found_time
<< ",\"shares_found\":" << shares_found
<< ",\"shares_failed\":" << shares_failed
<< ",\"average_effort\":" << average_effort
+3
View File
@@ -203,8 +203,11 @@ private:
double m_cumulativeFoundSharesDiff;
uint32_t m_totalFoundSidechainShares;
uint32_t m_totalFailedSidechainShares;
time_t m_lastSidechainShareFoundTime;
uint64_t m_totalStratumShares;
uint64_t m_banTime;
std::atomic<uint64_t> m_apiLastUpdateTime;
std::deque<SubmittedShare*> m_pendingShareChecks;
+2 -2
View File
@@ -1148,7 +1148,7 @@ bool TCPServer::Client::on_proxy_handshake(const char* data, uint32_t size)
switch (m_socks5ProxyState) {
case Socks5ProxyState::MethodSelectionSent:
if (m_numRead >= 2) {
if ((m_readBuf[0] != 5) && (m_readBuf[1] != 0)) {
if ((m_readBuf[0] != 5) || (m_readBuf[1] != 0)) {
LOGWARN(5, "SOCKS5 proxy returned an invalid METHOD selection message");
return false;
}
@@ -1192,7 +1192,7 @@ bool TCPServer::Client::on_proxy_handshake(const char* data, uint32_t size)
case Socks5ProxyState::ConnectRequestSent:
if (m_numRead >= 4) {
const uint8_t* p = reinterpret_cast<uint8_t*>(m_readBuf);
if ((p[0] != 5) && (p[1] != 0) && p[2] != 0) {
if ((p[0] != 5) || (p[1] != 0) || p[2] != 0) {
LOGWARN(5, "SOCKS5 proxy returned an invalid reply to CONNECT");
return false;
}
+1 -1
View File
@@ -35,7 +35,7 @@
namespace p2pool {
#define P2POOL_VERSION_MAJOR 4
#define P2POOL_VERSION_MINOR 7
#define P2POOL_VERSION_MINOR 8
#define P2POOL_VERSION_PATCH 0
constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;