Compare commits

..

33 Commits

Author SHA1 Message Date
SChernykh 0d7b110f15 Fix: more robust startup sequence 2025-05-29 17:44:08 +02:00
SChernykh 7cd21f5d0e p2pool v4.7 2025-05-29 13:43:07 +02:00
SChernykh 886da5a73e CI: fixed msys2 clang build 2025-05-29 09:16:03 +02:00
SChernykh bfa30254df Fixed build errors 2025-05-28 20:10:52 +02:00
SChernykh b589d373ea P2Pool-nano: display correct parameters at start-up 2025-05-28 17:47:18 +02:00
SChernykh 8333f7800f P2Pool-nano: fixed sync when using restricted RPC nodes 2025-05-28 17:13:16 +02:00
SChernykh 91fb15e967 Updated curl to 8.14.0 2025-05-28 16:16:12 +02:00
SChernykh e0c1d9377c P2Pool-nano support 2025-05-28 15:04:11 +02:00
SChernykh 3f80244d84 Updated miniupnp 2025-05-27 15:10:51 +02:00
SChernykh 433a1991bc Updated cppzmq 2025-05-27 15:07:40 +02:00
SChernykh 915be9e39f Tari: fixed max gRPC message size 2025-05-27 12:58:54 +02:00
SChernykh b9e415c659 Updated Tari gRPC proto files 2025-05-25 10:07:28 +02:00
SChernykh 1e2e5b85aa CI: don't build extra binaries when building tests 2025-05-23 10:45:40 +02:00
SChernykh 40999f0056 Fix: failure to connect to a node if its domain resolves to an IPv6 address 2025-05-21 10:34:22 +02:00
SChernykh cf51fe5273 p2pool v4.6 2025-05-17 09:05:09 +02:00
SChernykh 3154b61fc6 P2PServer: show protocol version in peer list 2025-05-16 09:40:14 +02:00
SChernykh f9831500e4 Fixed build 2025-05-16 08:11:22 +02:00
SChernykh e9d49b2a1d Added missing #ifdef 2025-05-15 23:21:47 +02:00
SChernykh 5eabfb0a1a Fixed Coverity errors 2025-05-15 22:38:54 +02:00
SChernykh 3fc68e680a Tweaked log messages 2025-05-15 18:43:22 +02:00
SChernykh 1bd9ff1379 Stratum local API: added wallet address 2025-05-15 16:32:44 +02:00
SChernykh 9a0a96f990 Merge pull request #349 from SChernykh/mm_donate
Merge mining donation support
2025-05-15 16:15:06 +02:00
SChernykh 604ef13aa6 Tari merge mining: added more checks 2025-05-15 12:28:07 +02:00
SChernykh 293c6f3930 Updated merge mining docs 2025-05-15 08:27:58 +02:00
SChernykh 1f3872254d Tari: more efficient polling
Use `GetTipInfo` gRPC call to quickly check for changes
2025-05-14 12:47:31 +02:00
SChernykh 27a2461d1d Tari: don't update the aux data too often if only fees change 2025-05-14 09:41:24 +02:00
SChernykh 70298cd065 Merge mining donation support 2025-05-13 17:18:29 +02:00
SChernykh f655fd1e30 Tari: smaller reconnect timeouts 2025-05-11 21:17:29 +02:00
SChernykh 9abe993bb0 Moved GCC 15 fix to flags.cmake 2025-05-07 18:33:30 +02:00
SChernykh 2a30901ba5 Added comments to PoolBlock::get_pow_hash
To explain what looks like a random magic code there
2025-05-07 16:21:27 +02:00
SChernykh 2c29092b7a Updated Tari merge mining docs 2025-05-06 20:02:39 +02:00
SChernykh 7d610f61d5 Sync test: updated Monero nodes 2025-05-04 10:39:48 +02:00
SChernykh 7d632fdc85 More informative main thread name 2025-05-03 17:53:51 +02:00
45 changed files with 2778 additions and 637 deletions
+10 -9
View File
@@ -2,6 +2,7 @@ name: C/C++ CI
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
@@ -88,7 +89,7 @@ jobs:
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 }}
make -j$(nproc)
make -j$(nproc) p2pool_tests
- name: Run tests
shell: alpine.sh {0}
@@ -156,7 +157,7 @@ jobs:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }} -DCMAKE_C_FLAGS='${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }}' -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc)
make -j$(nproc) p2pool_tests
- name: Run tests
run: |
@@ -236,7 +237,7 @@ jobs:
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 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc)
make -j$(nproc) p2pool_tests
- name: Run tests
run: |
@@ -315,7 +316,7 @@ jobs:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_STRIP=/usr/bin/aarch64-linux-gnu-strip -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=aarch64 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc)
make -j$(nproc) p2pool_tests
- name: Run tests
run: |
@@ -337,8 +338,8 @@ jobs:
strategy:
matrix:
config:
- {c: "gcc", cxx: "g++", flags: "-ffunction-sections -Wno-error=maybe-uninitialized -Wno-error=attributes -Wno-error=cpp"}
- {c: "clang", cxx: "clang++", flags: "-fuse-ld=lld -Wno-unused-command-line-argument -Wno-nan-infinity-disabled -Wno-error=cpp"}
- {c: "gcc", cxx: "g++", flags: "-ffunction-sections -Wno-error=maybe-uninitialized -Wno-error=attributes"}
- {c: "clang", cxx: "clang++", flags: "-fuse-ld=lld -Wno-unused-command-line-argument -Wno-nan-infinity-disabled"}
defaults:
run:
@@ -399,7 +400,7 @@ jobs:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} -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 -DOPENSSL_NO_ASM=ON
make -j$(nproc)
make -j$(nproc) p2pool_tests
- name: Run tests
run: |
@@ -540,7 +541,7 @@ jobs:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-flto -target x86_64-apple-macos10.13 -Wno-overriding-t-option' -DCMAKE_CXX_FLAGS='-flto -target x86_64-apple-macos10.13 -Wno-overriding-t-option' -DCMAKE_ASM_FLAGS='-target x86_64-apple-macos10.13' -DSTATIC_LIBS=ON
make -j4
make -j4 p2pool_tests
- name: Run tests
run: |
@@ -608,7 +609,7 @@ jobs:
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-target arm64-apple-macos-11" -DCMAKE_CXX_FLAGS="-target arm64-apple-macos-11" -DSTATIC_LIBS=ON -DWITH_LTO=OFF -DARCH_ID=aarch64
make -j3
make -j3 p2pool_tests
- name: Run tests
run: |
+1
View File
@@ -2,6 +2,7 @@ name: clang-tidy
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
+1
View File
@@ -13,6 +13,7 @@ name: "CodeQL"
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
+9 -8
View File
@@ -2,6 +2,7 @@ name: cppcheck
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
@@ -25,10 +26,10 @@ jobs:
submodules: recursive
- name: Checkout cppcheck
uses: actions/checkout@v4
with:
repository: danmar/cppcheck
path: cppcheck-main
run: |
git clone https://github.com/danmar/cppcheck cppcheck-main
cd cppcheck-main
git checkout 6d7dc76052ad36128fae93f994d6a2bf57e93103
- name: Build cppcheck
run: |
@@ -73,10 +74,10 @@ jobs:
submodules: recursive
- name: Checkout cppcheck
uses: actions/checkout@v4
with:
repository: danmar/cppcheck
path: cppcheck-main
run: |
git clone https://github.com/danmar/cppcheck cppcheck-main
cd cppcheck-main
git checkout 6d7dc76052ad36128fae93f994d6a2bf57e93103
- name: Build cppcheck
run: |
+1
View File
@@ -10,6 +10,7 @@ name: Microsoft C++ Code Analysis
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
+5 -1
View File
@@ -1,6 +1,10 @@
name: source-snapshot
on: [push, pull_request]
on:
push:
branches: ["master"]
pull_request:
jobs:
source-snapshot:
+8 -7
View File
@@ -2,6 +2,7 @@ name: Sync test
on:
push:
branches: ["master"]
paths-ignore:
- 'docker-compose/**'
- 'docs/**'
@@ -68,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -154,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -201,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -248,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -317,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -362,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
@@ -405,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 xmrbandwagon.hopto.org --rpc-port 18081 --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 --mini --out-peers 200 --data-api data --local-api --loglevel 6
- name: Check p2pool.log
run: |
+7 -1
View File
@@ -17,7 +17,9 @@ option(WITH_RANDOMX "Include the RandomX library in the build. If this is turned
option(WITH_LTO "Use link-time compiler optimization (if linking fails for you, run cmake with -DWITH_LTO=OFF)" ON)
option(WITH_UPNP "Include UPnP support. If this is turned off, p2pool will not be able to configure port forwarding on UPnP-enabled routers." ON)
option(WITH_GRPC "Include gRPC support. If this is turned off, p2pool will not be able to merge mine with Tari." ON)
option(WITH_TLS "Include TLS support. If this is turned off, p2pool will not support Stratum TLS connections." ON)
option(WITH_TLS "Include TLS support. If this is turned off, p2pool will not support Stratum TLS connections, and lack many other security features. It's recommended to keep it ON!" ON)
option(WITH_MERGE_MINING_DONATION "Merge mine donations to the author. This doesn't affect your hashrate or payouts in any way - only unused merge mining capacity will be utilised. If you merge mine yourself, your settings will take priority." ON)
option(DEV_TEST_SYNC "[Developer only] Sync test, stop p2pool after sync is complete" OFF)
option(DEV_WITH_TSAN "[Developer only] Compile with thread sanitizer" OFF)
@@ -56,6 +58,10 @@ if (WITH_UPNP)
set(LIBS ${LIBS} libminiupnpc-static)
endif()
if (WITH_MERGE_MINING_DONATION)
add_definitions(-DWITH_MERGE_MINING_DONATION)
endif()
if (DEV_TEST_SYNC)
add_definitions(-DDEV_TEST_SYNC)
endif()
+32 -6
View File
@@ -111,7 +111,7 @@ In order to continue mining on P2Pool, you must update both Monero and P2Pool so
### Merge mining
Merge mining will be available in P2Pool after the fork on October 12th, 2024. Version 4.0 or newer is required to use it.
Merge mining is available in P2Pool since the fork that happened on October 12th, 2024. Version 4.0 or newer is required to use it.
- 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)
@@ -120,11 +120,27 @@ Merge mining will be available in P2Pool after the fork on October 12th, 2024. V
p2pool.exe --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine IP:port YOUR_WALLET_ADDRESS_ON_ANOTHER_BLOCKCHAIN
```
- [Tari](https://www.tari.com/) uses their own gRPC API and requires a different command line:
```
p2pool.exe --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine tari://IP:port TARI_WALLET_ADDRESS
```
Merge mining is available for testing in Tari's [v1.0.0-pre.14 release](https://github.com/tari-project/tari/releases/tag/v1.0.0-pre.14) (Esmeralda testnet).
### Tari merge mining
[Tari](https://www.tari.com/) uses their own gRPC API and requires a different command line:
```
./p2pool --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine tari://TARI_NODE_IP:18102 TARI_WALLET_ADDRESS
```
and on the Tari side
```
./minotari_node --grpc-enabled --mining-enabled
```
TARI_NODE_IP is 127.0.0.1 if you run both on the same machine (recommended).
Merge mining is available on Tari's mainnet:
- Download [Tari suite](https://github.com/tari-project/tari/releases/latest) for your OS
- Run Minotari node and wait until in synchronizes
- Run Minotari console wallet to create a Tari wallet
- Copy the interactive wallet address from the "Receive" tab of the wallet
- Paste it into the P2Pool command line above
- Everything is ready now to start merge mining Monero and Tari!
Note that Tari will be mined in solo mode (only full Tari blocks can be mined for now). This doesn't affect P2Pool payouts - they will stay the same.
### GNU/Linux
@@ -349,3 +365,13 @@ If you'd like to support further development of Monero P2Pool, you're welcome to
```
44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg
```
Starting from v4.6, P2Pool will also have an ability to merge mine donations for the author.
Note that this will not affect your hashrate or payouts in any way. P2Pool will always (100% of the time) keep mining to your configured Monero wallet address, but it might also use the available merge mining capacity to donate to the author.
If you merge mine yourself, your settings will take priority.
The merge mining donation runs without a donation server - there is no "phoning home" to a server, everything is done through the P2Pool's network in a decentralized way.
To opt out of this, build P2Pool with `-DWITH_MERGE_MINING_DONATION=OFF` in cmake command line. Due to the architecture of the decentralized P2Pool network, your node will still relay donation messages to other nodes even if you opted out (but it will not process them).
+9 -1
View File
@@ -17,12 +17,16 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(GENERAL_FLAGS "${GENERAL_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
endif()
set(WARNING_FLAGS "-Wall -Wextra -Wcast-qual -Wlogical-op -Wundef -Wformat=2 -Wpointer-arith -Werror -Wno-error=inline -Wno-error=unused-function")
set(WARNING_FLAGS "-Wall -Wextra -Wcast-qual -Wlogical-op -Wundef -Wformat=2 -Wpointer-arith -Werror -Wno-error=inline -Wno-error=unused-function -Wno-error=strict-overflow")
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.5.0)
set(WARNING_FLAGS "${WARNING_FLAGS} -Wstrict-overflow=2")
endif()
if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15))
set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-error=cpp")
endif()
if (DISABLE_WARNINGS)
set(WARNING_FLAGS "-w")
endif()
@@ -111,6 +115,10 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(WARNING_FLAGS "-Wall -Wextra -Wno-unused-function -Wno-undefined-internal -Wunreachable-code-aggressive -Wmissing-prototypes -Wmissing-variable-declarations -Werror")
if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20))
set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-error=cpp")
endif()
if (DISABLE_WARNINGS)
set(WARNING_FLAGS "-w")
endif()
+1 -1
View File
@@ -1,5 +1,5 @@
@echo off
"..\cppcheck-main\bin\cppcheck.exe" ../src/*.cpp -D__cppcheck__ -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN -D_WIN32=1 -D_WIN64=1 -DWIN32=1 -D_WINDOWS=1 -DNDEBUG=1 -DWITH_GRPC=1 -DPROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII=0 -DWITH_RANDOMX=1 -DWITH_UPNP=1 -DCURL_STATICLIB=1 -DWIN32_LEAN_AND_MEAN=1 -D_WIN32_WINNT=0x0600 -D_DISABLE_VECTOR_ANNOTATION=1 -D_DISABLE_STRING_ANNOTATION=1 -DZMQ_STATIC=1 -DHAVE_BITSCANREVERSE64=1 -DRAPIDJSON_PARSE_DEFAULT_FLAGS=kParseTrailingCommasFlag -DMINIUPNP_STATICLIB=1 -DCARES_STATICLIB=1 -DCMAKE_INTDIR="Release" -D__SSE2__=1 -D_MSC_VER=1929 --platform=win64 --std=c++17 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt --max-ctu-depth=3 --check-level=exhaustive --checkers-report=checkers_report.txt
"..\cppcheck-main\bin\cppcheck.exe" ../src/*.cpp -D__cppcheck__ -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN -D_WIN32=1 -D_WIN64=1 -DWIN32=1 -D_WINDOWS=1 -DNDEBUG=1 -DWITH_GRPC=1 -DPROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII=0 -DWITH_RANDOMX=1 -DWITH_UPNP=1 -DWITH_TLS=1 -DWITH_MERGE_MINING_DONATION=1 -DCURL_STATICLIB=1 -DWIN32_LEAN_AND_MEAN=1 -D_WIN32_WINNT=0x0600 -D_DISABLE_VECTOR_ANNOTATION=1 -D_DISABLE_STRING_ANNOTATION=1 -DZMQ_STATIC=1 -DHAVE_BITSCANREVERSE64=1 -DRAPIDJSON_PARSE_DEFAULT_FLAGS=kParseTrailingCommasFlag -DMINIUPNP_STATICLIB=1 -DCARES_STATICLIB=1 -DCMAKE_INTDIR="Release" -D__SSE2__=1 -D_MSC_VER=1929 --platform=win64 --std=c++17 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt --max-ctu-depth=3 --check-level=exhaustive --checkers-report=checkers_report.txt
findstr /V /C:"external\src" errors_full.txt > errors_filtered0.txt
findstr /V /C:":checkersReport" errors_filtered0.txt > errors_filtered.txt
+24 -11
View File
@@ -22,6 +22,7 @@
--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 450)
--start-mining N Start built-in miner using N threads (any value between 1 and 64)
--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from 37889 to 37888
--nano Connect to p2pool-nano sidechain. Note that it will also change default p2p port from 37889 to 37890
--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
@@ -60,7 +61,7 @@ p2pool.exe --host 127.0.0.1 --host node.monerodevs.org --rpc-port 18089 --zmq-po
### Merge mining
Merge mining will be available in P2Pool after the fork on October 12th, 2024. Version 4.0 or newer is required to use it.
Merge mining is available in P2Pool since the fork that happened on October 12th, 2024. Version 4.0 or newer is required to use it.
- 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)
@@ -69,15 +70,27 @@ Merge mining will be available in P2Pool after the fork on October 12th, 2024. V
p2pool.exe --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine IP:port YOUR_WALLET_ADDRESS_ON_ANOTHER_BLOCKCHAIN
```
- [Tari](https://www.tari.com/) uses their own gRPC API and requires a different command line:
```
./p2pool --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine tari://IP:port TARI_WALLET_ADDRESS
```
and on the Tari side
```
./minotari_node --grpc-enabled --mining-enabled
```
Merge mining is available for testing in Tari's [latest release](https://github.com/tari-project/tari/releases) (Esmeralda testnet).
### Tari merge mining
[Tari](https://www.tari.com/) uses their own gRPC API and requires a different command line:
```
./p2pool --wallet YOUR_MONERO_WALLET_ADDRESS --merge-mine tari://TARI_NODE_IP:18102 TARI_WALLET_ADDRESS
```
and on the Tari side
```
./minotari_node --grpc-enabled --mining-enabled
```
TARI_NODE_IP is 127.0.0.1 if you run both on the same machine (recommended).
Merge mining is available on Tari's mainnet:
- Download [Tari suite](https://github.com/tari-project/tari/releases/latest) for your OS
- Run Minotari node and wait until in synchronizes
- Run Minotari console wallet to create a Tari wallet
- Copy the interactive wallet address from the "Receive" tab of the wallet
- Paste it into the P2Pool command line above
- Everything is ready now to start merge mining Monero and Tari!
Note that Tari will be mined in solo mode (only full Tari blocks can be mined for now). This doesn't affect P2Pool payouts - they will stay the same.
### TLS
@@ -101,4 +114,4 @@ P2Pool supports certificate pinning on RPC-SSL connections via `--rpc-ssl-finger
openssl x509 -in rpc_ssl.crt -pubkey -noout -inform pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
```
By default, `rpc_ssl.crt` can be found in Monero data directory: `/home/username/.bitmonero/rpc_ssl.crt` on Linux and `C:\ProgramData\bitmonero\rpc_ssl.crt` on Windows.
By default, `rpc_ssl.crt` can be found in Monero data directory: `/home/username/.bitmonero/rpc_ssl.crt` on Linux and `C:\ProgramData\bitmonero\rpc_ssl.crt` on Windows.
File diff suppressed because it is too large Load Diff
+640 -70
View File
@@ -172,6 +172,9 @@ extern ListAssetRegistrationsResponseDefaultTypeInternal _ListAssetRegistrations
class ListHeadersRequest;
struct ListHeadersRequestDefaultTypeInternal;
extern ListHeadersRequestDefaultTypeInternal _ListHeadersRequest_default_instance_;
class LivenessResult;
struct LivenessResultDefaultTypeInternal;
extern LivenessResultDefaultTypeInternal _LivenessResult_default_instance_;
class MempoolStatsResponse;
struct MempoolStatsResponseDefaultTypeInternal;
extern MempoolStatsResponseDefaultTypeInternal _MempoolStatsResponse_default_instance_;
@@ -583,20 +586,31 @@ class ValueAtHeightResponse final : public ::google::protobuf::Message
// accessors -------------------------------------------------------
enum : int {
kValueFieldNumber = 1,
kHeightFieldNumber = 2,
kCirculatingSupplyFieldNumber = 1,
kSpendableSupplyFieldNumber = 2,
kHeightFieldNumber = 3,
};
// uint64 value = 1;
void clear_value() ;
::uint64_t value() const;
void set_value(::uint64_t value);
// uint64 circulating_supply = 1;
void clear_circulating_supply() ;
::uint64_t circulating_supply() const;
void set_circulating_supply(::uint64_t value);
private:
::uint64_t _internal_value() const;
void _internal_set_value(::uint64_t value);
::uint64_t _internal_circulating_supply() const;
void _internal_set_circulating_supply(::uint64_t value);
public:
// uint64 height = 2;
// uint64 spendable_supply = 2;
void clear_spendable_supply() ;
::uint64_t spendable_supply() const;
void set_spendable_supply(::uint64_t value);
private:
::uint64_t _internal_spendable_supply() const;
void _internal_set_spendable_supply(::uint64_t value);
public:
// uint64 height = 3;
void clear_height() ;
::uint64_t height() const;
void set_height(::uint64_t value);
@@ -611,7 +625,7 @@ class ValueAtHeightResponse final : public ::google::protobuf::Message
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<
1, 2, 0,
2, 3, 0,
0, 2>
_table_;
friend class ::google::protobuf::MessageLite;
@@ -627,7 +641,8 @@ class ValueAtHeightResponse final : public ::google::protobuf::Message
::google::protobuf::Arena* arena);
inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility,
::google::protobuf::Arena* arena, const Impl_& from);
::uint64_t value_;
::uint64_t circulating_supply_;
::uint64_t spendable_supply_;
::uint64_t height_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
PROTOBUF_TSAN_DECLARE_MEMBER
@@ -2291,8 +2306,9 @@ class NetworkDifficultyResponse final : public ::google::protobuf::Message
kTimestampFieldNumber = 4,
kPowAlgoFieldNumber = 5,
kSha3XEstimatedHashRateFieldNumber = 6,
kRandomxEstimatedHashRateFieldNumber = 7,
kMoneroRandomxEstimatedHashRateFieldNumber = 7,
kNumCoinbasesFieldNumber = 8,
kTariRandomxEstimatedHashRateFieldNumber = 10,
};
// repeated bytes coinbase_extras = 9;
int coinbase_extras_size() const;
@@ -2382,14 +2398,14 @@ class NetworkDifficultyResponse final : public ::google::protobuf::Message
void _internal_set_sha3x_estimated_hash_rate(::uint64_t value);
public:
// uint64 randomx_estimated_hash_rate = 7;
void clear_randomx_estimated_hash_rate() ;
::uint64_t randomx_estimated_hash_rate() const;
void set_randomx_estimated_hash_rate(::uint64_t value);
// uint64 monero_randomx_estimated_hash_rate = 7;
void clear_monero_randomx_estimated_hash_rate() ;
::uint64_t monero_randomx_estimated_hash_rate() const;
void set_monero_randomx_estimated_hash_rate(::uint64_t value);
private:
::uint64_t _internal_randomx_estimated_hash_rate() const;
void _internal_set_randomx_estimated_hash_rate(::uint64_t value);
::uint64_t _internal_monero_randomx_estimated_hash_rate() const;
void _internal_set_monero_randomx_estimated_hash_rate(::uint64_t value);
public:
// uint64 num_coinbases = 8;
@@ -2401,13 +2417,23 @@ class NetworkDifficultyResponse final : public ::google::protobuf::Message
::uint64_t _internal_num_coinbases() const;
void _internal_set_num_coinbases(::uint64_t value);
public:
// uint64 tari_randomx_estimated_hash_rate = 10;
void clear_tari_randomx_estimated_hash_rate() ;
::uint64_t tari_randomx_estimated_hash_rate() const;
void set_tari_randomx_estimated_hash_rate(::uint64_t value);
private:
::uint64_t _internal_tari_randomx_estimated_hash_rate() const;
void _internal_set_tari_randomx_estimated_hash_rate(::uint64_t value);
public:
// @@protoc_insertion_point(class_scope:tari.rpc.NetworkDifficultyResponse)
private:
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<
4, 9, 0,
4, 10, 0,
0, 2>
_table_;
friend class ::google::protobuf::MessageLite;
@@ -2430,8 +2456,9 @@ class NetworkDifficultyResponse final : public ::google::protobuf::Message
::uint64_t timestamp_;
::uint64_t pow_algo_;
::uint64_t sha3x_estimated_hash_rate_;
::uint64_t randomx_estimated_hash_rate_;
::uint64_t monero_randomx_estimated_hash_rate_;
::uint64_t num_coinbases_;
::uint64_t tari_randomx_estimated_hash_rate_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
PROTOBUF_TSAN_DECLARE_MEMBER
};
@@ -2858,6 +2885,203 @@ class MempoolStatsResponse final : public ::google::protobuf::Message
};
// -------------------------------------------------------------------
class LivenessResult final : public ::google::protobuf::Message
/* @@protoc_insertion_point(class_definition:tari.rpc.LivenessResult) */ {
public:
inline LivenessResult() : LivenessResult(nullptr) {}
~LivenessResult() override;
template <typename = void>
explicit PROTOBUF_CONSTEXPR LivenessResult(
::google::protobuf::internal::ConstantInitialized);
inline LivenessResult(const LivenessResult& from) : LivenessResult(nullptr, from) {}
inline LivenessResult(LivenessResult&& from) noexcept
: LivenessResult(nullptr, std::move(from)) {}
inline LivenessResult& operator=(const LivenessResult& from) {
CopyFrom(from);
return *this;
}
inline LivenessResult& operator=(LivenessResult&& from) noexcept {
if (this == &from) return *this;
if (GetArena() == from.GetArena()
#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
&& GetArena() != nullptr
#endif // !PROTOBUF_FORCE_COPY_IN_MOVE
) {
InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance);
}
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields()
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>();
}
static const ::google::protobuf::Descriptor* descriptor() {
return GetDescriptor();
}
static const ::google::protobuf::Descriptor* GetDescriptor() {
return default_instance().GetMetadata().descriptor;
}
static const ::google::protobuf::Reflection* GetReflection() {
return default_instance().GetMetadata().reflection;
}
static const LivenessResult& default_instance() {
return *internal_default_instance();
}
static inline const LivenessResult* internal_default_instance() {
return reinterpret_cast<const LivenessResult*>(
&_LivenessResult_default_instance_);
}
static constexpr int kIndexInFileMessages = 57;
friend void swap(LivenessResult& a, LivenessResult& b) { a.Swap(&b); }
inline void Swap(LivenessResult* other) {
if (other == this) return;
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
if (GetArena() != nullptr && GetArena() == other->GetArena()) {
#else // PROTOBUF_FORCE_COPY_IN_SWAP
if (GetArena() == other->GetArena()) {
#endif // !PROTOBUF_FORCE_COPY_IN_SWAP
InternalSwap(other);
} else {
::google::protobuf::internal::GenericSwap(this, other);
}
}
void UnsafeArenaSwap(LivenessResult* other) {
if (other == this) return;
ABSL_DCHECK(GetArena() == other->GetArena());
InternalSwap(other);
}
// implements Message ----------------------------------------------
LivenessResult* New(::google::protobuf::Arena* arena = nullptr) const final {
return ::google::protobuf::Message::DefaultConstruct<LivenessResult>(arena);
}
using ::google::protobuf::Message::CopyFrom;
void CopyFrom(const LivenessResult& from);
using ::google::protobuf::Message::MergeFrom;
void MergeFrom(const LivenessResult& from) { LivenessResult::MergeImpl(*this, from); }
private:
static void MergeImpl(
::google::protobuf::MessageLite& to_msg,
const ::google::protobuf::MessageLite& from_msg);
public:
ABSL_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
::size_t ByteSizeLong() const final;
const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
::uint8_t* _InternalSerialize(
::uint8_t* target,
::google::protobuf::io::EpsCopyOutputStream* stream) const final;
int GetCachedSize() const { return _impl_._cached_size_.Get(); }
private:
void SharedCtor(::google::protobuf::Arena* arena);
void SharedDtor();
void InternalSwap(LivenessResult* other);
private:
friend class ::google::protobuf::internal::AnyMetadata;
static ::absl::string_view FullMessageName() { return "tari.rpc.LivenessResult"; }
protected:
explicit LivenessResult(::google::protobuf::Arena* arena);
LivenessResult(::google::protobuf::Arena* arena, const LivenessResult& from);
LivenessResult(::google::protobuf::Arena* arena, LivenessResult&& from) noexcept
: LivenessResult(arena) {
*this = ::std::move(from);
}
const ::google::protobuf::MessageLite::ClassData* GetClassData()
const final;
public:
::google::protobuf::Metadata GetMetadata() const final;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
enum : int {
kPeerNodeIdFieldNumber = 1,
kDiscoverLatencyFieldNumber = 2,
kPingLatencyFieldNumber = 3,
};
// bytes peer_node_id = 1;
void clear_peer_node_id() ;
const std::string& peer_node_id() const;
template <typename Arg_ = const std::string&, typename... Args_>
void set_peer_node_id(Arg_&& arg, Args_... args);
std::string* mutable_peer_node_id();
PROTOBUF_NODISCARD std::string* release_peer_node_id();
void set_allocated_peer_node_id(std::string* value);
private:
const std::string& _internal_peer_node_id() const;
inline PROTOBUF_ALWAYS_INLINE void _internal_set_peer_node_id(
const std::string& value);
std::string* _internal_mutable_peer_node_id();
public:
// uint64 discover_latency = 2;
void clear_discover_latency() ;
::uint64_t discover_latency() const;
void set_discover_latency(::uint64_t value);
private:
::uint64_t _internal_discover_latency() const;
void _internal_set_discover_latency(::uint64_t value);
public:
// uint64 ping_latency = 3;
void clear_ping_latency() ;
::uint64_t ping_latency() const;
void set_ping_latency(::uint64_t value);
private:
::uint64_t _internal_ping_latency() const;
void _internal_set_ping_latency(::uint64_t value);
public:
// @@protoc_insertion_point(class_scope:tari.rpc.LivenessResult)
private:
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<
2, 3, 0,
0, 2>
_table_;
friend class ::google::protobuf::MessageLite;
friend class ::google::protobuf::Arena;
template <typename T>
friend class ::google::protobuf::Arena::InternalHelper;
using InternalArenaConstructable_ = void;
using DestructorSkippable_ = void;
struct Impl_ {
inline explicit constexpr Impl_(
::google::protobuf::internal::ConstantInitialized) noexcept;
inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility,
::google::protobuf::Arena* arena);
inline explicit Impl_(::google::protobuf::internal::InternalVisibility visibility,
::google::protobuf::Arena* arena, const Impl_& from);
::google::protobuf::internal::ArenaStringPtr peer_node_id_;
::uint64_t discover_latency_;
::uint64_t ping_latency_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
PROTOBUF_TSAN_DECLARE_MEMBER
};
union { Impl_ _impl_; };
friend struct ::TableStruct_base_5fnode_2eproto;
};
// -------------------------------------------------------------------
class ListHeadersRequest final : public ::google::protobuf::Message
/* @@protoc_insertion_point(class_definition:tari.rpc.ListHeadersRequest) */ {
public:
@@ -8495,14 +8719,34 @@ class GetNetworkStateResponse final : public ::google::protobuf::Message
// accessors -------------------------------------------------------
enum : int {
kLivenessResultsFieldNumber = 9,
kMetadataFieldNumber = 1,
kBaseNodeStateFieldNumber = 3,
kInitialSyncAchievedFieldNumber = 2,
kFailedCheckpointsFieldNumber = 4,
kRewardFieldNumber = 5,
kSha3XEstimatedHashRateFieldNumber = 6,
kRandomxEstimatedHashRateFieldNumber = 7,
kMoneroRandomxEstimatedHashRateFieldNumber = 7,
kNumConnectionsFieldNumber = 8,
kTariRandomxEstimatedHashRateFieldNumber = 10,
};
// repeated .tari.rpc.LivenessResult liveness_results = 9;
int liveness_results_size() const;
private:
int _internal_liveness_results_size() const;
public:
void clear_liveness_results() ;
::tari::rpc::LivenessResult* mutable_liveness_results(int index);
::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>* mutable_liveness_results();
private:
const ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>& _internal_liveness_results() const;
::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>* _internal_mutable_liveness_results();
public:
const ::tari::rpc::LivenessResult& liveness_results(int index) const;
::tari::rpc::LivenessResult* add_liveness_results();
const ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>& liveness_results() const;
// .tari.rpc.MetaData metadata = 1;
bool has_metadata() const;
void clear_metadata() ;
@@ -8568,14 +8812,34 @@ class GetNetworkStateResponse final : public ::google::protobuf::Message
void _internal_set_sha3x_estimated_hash_rate(::uint64_t value);
public:
// uint64 randomx_estimated_hash_rate = 7;
void clear_randomx_estimated_hash_rate() ;
::uint64_t randomx_estimated_hash_rate() const;
void set_randomx_estimated_hash_rate(::uint64_t value);
// uint64 monero_randomx_estimated_hash_rate = 7;
void clear_monero_randomx_estimated_hash_rate() ;
::uint64_t monero_randomx_estimated_hash_rate() const;
void set_monero_randomx_estimated_hash_rate(::uint64_t value);
private:
::uint64_t _internal_randomx_estimated_hash_rate() const;
void _internal_set_randomx_estimated_hash_rate(::uint64_t value);
::uint64_t _internal_monero_randomx_estimated_hash_rate() const;
void _internal_set_monero_randomx_estimated_hash_rate(::uint64_t value);
public:
// uint64 num_connections = 8;
void clear_num_connections() ;
::uint64_t num_connections() const;
void set_num_connections(::uint64_t value);
private:
::uint64_t _internal_num_connections() const;
void _internal_set_num_connections(::uint64_t value);
public:
// uint64 tari_randomx_estimated_hash_rate = 10;
void clear_tari_randomx_estimated_hash_rate() ;
::uint64_t tari_randomx_estimated_hash_rate() const;
void set_tari_randomx_estimated_hash_rate(::uint64_t value);
private:
::uint64_t _internal_tari_randomx_estimated_hash_rate() const;
void _internal_set_tari_randomx_estimated_hash_rate(::uint64_t value);
public:
// @@protoc_insertion_point(class_scope:tari.rpc.GetNetworkStateResponse)
@@ -8583,7 +8847,7 @@ class GetNetworkStateResponse final : public ::google::protobuf::Message
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<
3, 7, 1,
4, 10, 2,
0, 2>
_table_;
friend class ::google::protobuf::MessageLite;
@@ -8601,13 +8865,16 @@ class GetNetworkStateResponse final : public ::google::protobuf::Message
::google::protobuf::Arena* arena, const Impl_& from);
::google::protobuf::internal::HasBits<1> _has_bits_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::RepeatedPtrField< ::tari::rpc::LivenessResult > liveness_results_;
::tari::rpc::MetaData* metadata_;
int base_node_state_;
bool initial_sync_achieved_;
bool failed_checkpoints_;
::uint64_t reward_;
::uint64_t sha3x_estimated_hash_rate_;
::uint64_t randomx_estimated_hash_rate_;
::uint64_t monero_randomx_estimated_hash_rate_;
::uint64_t num_connections_;
::uint64_t tari_randomx_estimated_hash_rate_;
PROTOBUF_TSAN_DECLARE_MEMBER
};
union { Impl_ _impl_; };
@@ -11085,6 +11352,7 @@ class GetNewBlockResult final : public ::google::protobuf::Message
kBlockHashFieldNumber = 1,
kMergeMiningHashFieldNumber = 3,
kTariUniqueIdFieldNumber = 4,
kVmKeyFieldNumber = 6,
kBlockFieldNumber = 2,
kMinerDataFieldNumber = 5,
};
@@ -11135,6 +11403,22 @@ class GetNewBlockResult final : public ::google::protobuf::Message
const std::string& value);
std::string* _internal_mutable_tari_unique_id();
public:
// bytes vm_key = 6;
void clear_vm_key() ;
const std::string& vm_key() const;
template <typename Arg_ = const std::string&, typename... Args_>
void set_vm_key(Arg_&& arg, Args_... args);
std::string* mutable_vm_key();
PROTOBUF_NODISCARD std::string* release_vm_key();
void set_allocated_vm_key(std::string* value);
private:
const std::string& _internal_vm_key() const;
inline PROTOBUF_ALWAYS_INLINE void _internal_set_vm_key(
const std::string& value);
std::string* _internal_mutable_vm_key();
public:
// .tari.rpc.Block block = 2;
bool has_block() const;
@@ -11171,7 +11455,7 @@ class GetNewBlockResult final : public ::google::protobuf::Message
class _Internal;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<
3, 5, 2,
3, 6, 2,
0, 2>
_table_;
friend class ::google::protobuf::MessageLite;
@@ -11192,6 +11476,7 @@ class GetNewBlockResult final : public ::google::protobuf::Message
::google::protobuf::internal::ArenaStringPtr block_hash_;
::google::protobuf::internal::ArenaStringPtr merge_mining_hash_;
::google::protobuf::internal::ArenaStringPtr tari_unique_id_;
::google::protobuf::internal::ArenaStringPtr vm_key_;
::tari::rpc::Block* block_;
::tari::rpc::MinerData* miner_data_;
PROTOBUF_TSAN_DECLARE_MEMBER
@@ -14188,26 +14473,48 @@ inline void NetworkDifficultyResponse::_internal_set_sha3x_estimated_hash_rate(:
_impl_.sha3x_estimated_hash_rate_ = value;
}
// uint64 randomx_estimated_hash_rate = 7;
inline void NetworkDifficultyResponse::clear_randomx_estimated_hash_rate() {
// uint64 monero_randomx_estimated_hash_rate = 7;
inline void NetworkDifficultyResponse::clear_monero_randomx_estimated_hash_rate() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.randomx_estimated_hash_rate_ = ::uint64_t{0u};
_impl_.monero_randomx_estimated_hash_rate_ = ::uint64_t{0u};
}
inline ::uint64_t NetworkDifficultyResponse::randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.NetworkDifficultyResponse.randomx_estimated_hash_rate)
return _internal_randomx_estimated_hash_rate();
inline ::uint64_t NetworkDifficultyResponse::monero_randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.NetworkDifficultyResponse.monero_randomx_estimated_hash_rate)
return _internal_monero_randomx_estimated_hash_rate();
}
inline void NetworkDifficultyResponse::set_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.NetworkDifficultyResponse.randomx_estimated_hash_rate)
inline void NetworkDifficultyResponse::set_monero_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_monero_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.NetworkDifficultyResponse.monero_randomx_estimated_hash_rate)
}
inline ::uint64_t NetworkDifficultyResponse::_internal_randomx_estimated_hash_rate() const {
inline ::uint64_t NetworkDifficultyResponse::_internal_monero_randomx_estimated_hash_rate() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.randomx_estimated_hash_rate_;
return _impl_.monero_randomx_estimated_hash_rate_;
}
inline void NetworkDifficultyResponse::_internal_set_randomx_estimated_hash_rate(::uint64_t value) {
inline void NetworkDifficultyResponse::_internal_set_monero_randomx_estimated_hash_rate(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.randomx_estimated_hash_rate_ = value;
_impl_.monero_randomx_estimated_hash_rate_ = value;
}
// uint64 tari_randomx_estimated_hash_rate = 10;
inline void NetworkDifficultyResponse::clear_tari_randomx_estimated_hash_rate() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.tari_randomx_estimated_hash_rate_ = ::uint64_t{0u};
}
inline ::uint64_t NetworkDifficultyResponse::tari_randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.NetworkDifficultyResponse.tari_randomx_estimated_hash_rate)
return _internal_tari_randomx_estimated_hash_rate();
}
inline void NetworkDifficultyResponse::set_tari_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_tari_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.NetworkDifficultyResponse.tari_randomx_estimated_hash_rate)
}
inline ::uint64_t NetworkDifficultyResponse::_internal_tari_randomx_estimated_hash_rate() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.tari_randomx_estimated_hash_rate_;
}
inline void NetworkDifficultyResponse::_internal_set_tari_randomx_estimated_hash_rate(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.tari_randomx_estimated_hash_rate_ = value;
}
// uint64 num_coinbases = 8;
@@ -14338,29 +14645,51 @@ NetworkDifficultyResponse::_internal_mutable_coinbase_extras() {
// ValueAtHeightResponse
// uint64 value = 1;
inline void ValueAtHeightResponse::clear_value() {
// uint64 circulating_supply = 1;
inline void ValueAtHeightResponse::clear_circulating_supply() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.value_ = ::uint64_t{0u};
_impl_.circulating_supply_ = ::uint64_t{0u};
}
inline ::uint64_t ValueAtHeightResponse::value() const {
// @@protoc_insertion_point(field_get:tari.rpc.ValueAtHeightResponse.value)
return _internal_value();
inline ::uint64_t ValueAtHeightResponse::circulating_supply() const {
// @@protoc_insertion_point(field_get:tari.rpc.ValueAtHeightResponse.circulating_supply)
return _internal_circulating_supply();
}
inline void ValueAtHeightResponse::set_value(::uint64_t value) {
_internal_set_value(value);
// @@protoc_insertion_point(field_set:tari.rpc.ValueAtHeightResponse.value)
inline void ValueAtHeightResponse::set_circulating_supply(::uint64_t value) {
_internal_set_circulating_supply(value);
// @@protoc_insertion_point(field_set:tari.rpc.ValueAtHeightResponse.circulating_supply)
}
inline ::uint64_t ValueAtHeightResponse::_internal_value() const {
inline ::uint64_t ValueAtHeightResponse::_internal_circulating_supply() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.value_;
return _impl_.circulating_supply_;
}
inline void ValueAtHeightResponse::_internal_set_value(::uint64_t value) {
inline void ValueAtHeightResponse::_internal_set_circulating_supply(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.value_ = value;
_impl_.circulating_supply_ = value;
}
// uint64 height = 2;
// uint64 spendable_supply = 2;
inline void ValueAtHeightResponse::clear_spendable_supply() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.spendable_supply_ = ::uint64_t{0u};
}
inline ::uint64_t ValueAtHeightResponse::spendable_supply() const {
// @@protoc_insertion_point(field_get:tari.rpc.ValueAtHeightResponse.spendable_supply)
return _internal_spendable_supply();
}
inline void ValueAtHeightResponse::set_spendable_supply(::uint64_t value) {
_internal_set_spendable_supply(value);
// @@protoc_insertion_point(field_set:tari.rpc.ValueAtHeightResponse.spendable_supply)
}
inline ::uint64_t ValueAtHeightResponse::_internal_spendable_supply() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.spendable_supply_;
}
inline void ValueAtHeightResponse::_internal_set_spendable_supply(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.spendable_supply_ = value;
}
// uint64 height = 3;
inline void ValueAtHeightResponse::clear_height() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.height_ = ::uint64_t{0u};
@@ -15973,6 +16302,56 @@ inline void GetNewBlockResult::set_allocated_miner_data(::tari::rpc::MinerData*
// @@protoc_insertion_point(field_set_allocated:tari.rpc.GetNewBlockResult.miner_data)
}
// bytes vm_key = 6;
inline void GetNewBlockResult::clear_vm_key() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.vm_key_.ClearToEmpty();
}
inline const std::string& GetNewBlockResult::vm_key() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_get:tari.rpc.GetNewBlockResult.vm_key)
return _internal_vm_key();
}
template <typename Arg_, typename... Args_>
inline PROTOBUF_ALWAYS_INLINE void GetNewBlockResult::set_vm_key(Arg_&& arg,
Args_... args) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.vm_key_.SetBytes(static_cast<Arg_&&>(arg), args..., GetArena());
// @@protoc_insertion_point(field_set:tari.rpc.GetNewBlockResult.vm_key)
}
inline std::string* GetNewBlockResult::mutable_vm_key() ABSL_ATTRIBUTE_LIFETIME_BOUND {
std::string* _s = _internal_mutable_vm_key();
// @@protoc_insertion_point(field_mutable:tari.rpc.GetNewBlockResult.vm_key)
return _s;
}
inline const std::string& GetNewBlockResult::_internal_vm_key() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.vm_key_.Get();
}
inline void GetNewBlockResult::_internal_set_vm_key(const std::string& value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.vm_key_.Set(value, GetArena());
}
inline std::string* GetNewBlockResult::_internal_mutable_vm_key() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _impl_.vm_key_.Mutable( GetArena());
}
inline std::string* GetNewBlockResult::release_vm_key() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
// @@protoc_insertion_point(field_release:tari.rpc.GetNewBlockResult.vm_key)
return _impl_.vm_key_.Release();
}
inline void GetNewBlockResult::set_allocated_vm_key(std::string* value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.vm_key_.SetAllocated(value, GetArena());
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
if (_impl_.vm_key_.IsDefault()) {
_impl_.vm_key_.Set("", GetArena());
}
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
// @@protoc_insertion_point(field_set_allocated:tari.rpc.GetNewBlockResult.vm_key)
}
// -------------------------------------------------------------------
// GetNewBlockBlobResult
@@ -18368,26 +18747,217 @@ inline void GetNetworkStateResponse::_internal_set_sha3x_estimated_hash_rate(::u
_impl_.sha3x_estimated_hash_rate_ = value;
}
// uint64 randomx_estimated_hash_rate = 7;
inline void GetNetworkStateResponse::clear_randomx_estimated_hash_rate() {
// uint64 monero_randomx_estimated_hash_rate = 7;
inline void GetNetworkStateResponse::clear_monero_randomx_estimated_hash_rate() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.randomx_estimated_hash_rate_ = ::uint64_t{0u};
_impl_.monero_randomx_estimated_hash_rate_ = ::uint64_t{0u};
}
inline ::uint64_t GetNetworkStateResponse::randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.GetNetworkStateResponse.randomx_estimated_hash_rate)
return _internal_randomx_estimated_hash_rate();
inline ::uint64_t GetNetworkStateResponse::monero_randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.GetNetworkStateResponse.monero_randomx_estimated_hash_rate)
return _internal_monero_randomx_estimated_hash_rate();
}
inline void GetNetworkStateResponse::set_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.GetNetworkStateResponse.randomx_estimated_hash_rate)
inline void GetNetworkStateResponse::set_monero_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_monero_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.GetNetworkStateResponse.monero_randomx_estimated_hash_rate)
}
inline ::uint64_t GetNetworkStateResponse::_internal_randomx_estimated_hash_rate() const {
inline ::uint64_t GetNetworkStateResponse::_internal_monero_randomx_estimated_hash_rate() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.randomx_estimated_hash_rate_;
return _impl_.monero_randomx_estimated_hash_rate_;
}
inline void GetNetworkStateResponse::_internal_set_randomx_estimated_hash_rate(::uint64_t value) {
inline void GetNetworkStateResponse::_internal_set_monero_randomx_estimated_hash_rate(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.randomx_estimated_hash_rate_ = value;
_impl_.monero_randomx_estimated_hash_rate_ = value;
}
// uint64 tari_randomx_estimated_hash_rate = 10;
inline void GetNetworkStateResponse::clear_tari_randomx_estimated_hash_rate() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.tari_randomx_estimated_hash_rate_ = ::uint64_t{0u};
}
inline ::uint64_t GetNetworkStateResponse::tari_randomx_estimated_hash_rate() const {
// @@protoc_insertion_point(field_get:tari.rpc.GetNetworkStateResponse.tari_randomx_estimated_hash_rate)
return _internal_tari_randomx_estimated_hash_rate();
}
inline void GetNetworkStateResponse::set_tari_randomx_estimated_hash_rate(::uint64_t value) {
_internal_set_tari_randomx_estimated_hash_rate(value);
// @@protoc_insertion_point(field_set:tari.rpc.GetNetworkStateResponse.tari_randomx_estimated_hash_rate)
}
inline ::uint64_t GetNetworkStateResponse::_internal_tari_randomx_estimated_hash_rate() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.tari_randomx_estimated_hash_rate_;
}
inline void GetNetworkStateResponse::_internal_set_tari_randomx_estimated_hash_rate(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.tari_randomx_estimated_hash_rate_ = value;
}
// uint64 num_connections = 8;
inline void GetNetworkStateResponse::clear_num_connections() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.num_connections_ = ::uint64_t{0u};
}
inline ::uint64_t GetNetworkStateResponse::num_connections() const {
// @@protoc_insertion_point(field_get:tari.rpc.GetNetworkStateResponse.num_connections)
return _internal_num_connections();
}
inline void GetNetworkStateResponse::set_num_connections(::uint64_t value) {
_internal_set_num_connections(value);
// @@protoc_insertion_point(field_set:tari.rpc.GetNetworkStateResponse.num_connections)
}
inline ::uint64_t GetNetworkStateResponse::_internal_num_connections() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.num_connections_;
}
inline void GetNetworkStateResponse::_internal_set_num_connections(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.num_connections_ = value;
}
// repeated .tari.rpc.LivenessResult liveness_results = 9;
inline int GetNetworkStateResponse::_internal_liveness_results_size() const {
return _internal_liveness_results().size();
}
inline int GetNetworkStateResponse::liveness_results_size() const {
return _internal_liveness_results_size();
}
inline void GetNetworkStateResponse::clear_liveness_results() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.liveness_results_.Clear();
}
inline ::tari::rpc::LivenessResult* GetNetworkStateResponse::mutable_liveness_results(int index)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_mutable:tari.rpc.GetNetworkStateResponse.liveness_results)
return _internal_mutable_liveness_results()->Mutable(index);
}
inline ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>* GetNetworkStateResponse::mutable_liveness_results()
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_mutable_list:tari.rpc.GetNetworkStateResponse.liveness_results)
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _internal_mutable_liveness_results();
}
inline const ::tari::rpc::LivenessResult& GetNetworkStateResponse::liveness_results(int index) const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_get:tari.rpc.GetNetworkStateResponse.liveness_results)
return _internal_liveness_results().Get(index);
}
inline ::tari::rpc::LivenessResult* GetNetworkStateResponse::add_liveness_results() ABSL_ATTRIBUTE_LIFETIME_BOUND {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
::tari::rpc::LivenessResult* _add = _internal_mutable_liveness_results()->Add();
// @@protoc_insertion_point(field_add:tari.rpc.GetNetworkStateResponse.liveness_results)
return _add;
}
inline const ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>& GetNetworkStateResponse::liveness_results() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_list:tari.rpc.GetNetworkStateResponse.liveness_results)
return _internal_liveness_results();
}
inline const ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>&
GetNetworkStateResponse::_internal_liveness_results() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.liveness_results_;
}
inline ::google::protobuf::RepeatedPtrField<::tari::rpc::LivenessResult>*
GetNetworkStateResponse::_internal_mutable_liveness_results() {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return &_impl_.liveness_results_;
}
// -------------------------------------------------------------------
// LivenessResult
// bytes peer_node_id = 1;
inline void LivenessResult::clear_peer_node_id() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.peer_node_id_.ClearToEmpty();
}
inline const std::string& LivenessResult::peer_node_id() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// @@protoc_insertion_point(field_get:tari.rpc.LivenessResult.peer_node_id)
return _internal_peer_node_id();
}
template <typename Arg_, typename... Args_>
inline PROTOBUF_ALWAYS_INLINE void LivenessResult::set_peer_node_id(Arg_&& arg,
Args_... args) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.peer_node_id_.SetBytes(static_cast<Arg_&&>(arg), args..., GetArena());
// @@protoc_insertion_point(field_set:tari.rpc.LivenessResult.peer_node_id)
}
inline std::string* LivenessResult::mutable_peer_node_id() ABSL_ATTRIBUTE_LIFETIME_BOUND {
std::string* _s = _internal_mutable_peer_node_id();
// @@protoc_insertion_point(field_mutable:tari.rpc.LivenessResult.peer_node_id)
return _s;
}
inline const std::string& LivenessResult::_internal_peer_node_id() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.peer_node_id_.Get();
}
inline void LivenessResult::_internal_set_peer_node_id(const std::string& value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.peer_node_id_.Set(value, GetArena());
}
inline std::string* LivenessResult::_internal_mutable_peer_node_id() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
return _impl_.peer_node_id_.Mutable( GetArena());
}
inline std::string* LivenessResult::release_peer_node_id() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
// @@protoc_insertion_point(field_release:tari.rpc.LivenessResult.peer_node_id)
return _impl_.peer_node_id_.Release();
}
inline void LivenessResult::set_allocated_peer_node_id(std::string* value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.peer_node_id_.SetAllocated(value, GetArena());
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
if (_impl_.peer_node_id_.IsDefault()) {
_impl_.peer_node_id_.Set("", GetArena());
}
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
// @@protoc_insertion_point(field_set_allocated:tari.rpc.LivenessResult.peer_node_id)
}
// uint64 discover_latency = 2;
inline void LivenessResult::clear_discover_latency() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.discover_latency_ = ::uint64_t{0u};
}
inline ::uint64_t LivenessResult::discover_latency() const {
// @@protoc_insertion_point(field_get:tari.rpc.LivenessResult.discover_latency)
return _internal_discover_latency();
}
inline void LivenessResult::set_discover_latency(::uint64_t value) {
_internal_set_discover_latency(value);
// @@protoc_insertion_point(field_set:tari.rpc.LivenessResult.discover_latency)
}
inline ::uint64_t LivenessResult::_internal_discover_latency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.discover_latency_;
}
inline void LivenessResult::_internal_set_discover_latency(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.discover_latency_ = value;
}
// uint64 ping_latency = 3;
inline void LivenessResult::clear_ping_latency() {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.ping_latency_ = ::uint64_t{0u};
}
inline ::uint64_t LivenessResult::ping_latency() const {
// @@protoc_insertion_point(field_get:tari.rpc.LivenessResult.ping_latency)
return _internal_ping_latency();
}
inline void LivenessResult::set_ping_latency(::uint64_t value) {
_internal_set_ping_latency(value);
// @@protoc_insertion_point(field_set:tari.rpc.LivenessResult.ping_latency)
}
inline ::uint64_t LivenessResult::_internal_ping_latency() const {
PROTOBUF_TSAN_READ(&_impl_._tsan_detect_race);
return _impl_.ping_latency_;
}
inline void LivenessResult::_internal_set_ping_latency(::uint64_t value) {
PROTOBUF_TSAN_WRITE(&_impl_._tsan_detect_race);
_impl_.ping_latency_ = value;
}
#ifdef __GNUC__
+21 -4
View File
@@ -218,15 +218,17 @@ message NetworkDifficultyResponse {
uint64 timestamp = 4;
uint64 pow_algo = 5;
uint64 sha3x_estimated_hash_rate = 6;
uint64 randomx_estimated_hash_rate = 7;
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
uint64 num_coinbases = 8;
repeated bytes coinbase_extras = 9;
}
// A generic single value response for a specific height
message ValueAtHeightResponse {
uint64 value= 1;
uint64 height = 2;
uint64 circulating_supply = 1;
uint64 spendable_supply = 2;
uint64 height = 3;
}
// A generic uint value
@@ -382,6 +384,7 @@ message GetNewBlockResult{
bytes merge_mining_hash =3;
bytes tari_unique_id =4;
MinerData miner_data = 5;
bytes vm_key = 6;
}
// This is the message that is returned for a miner after it asks for a new block.
@@ -539,6 +542,20 @@ message GetNetworkStateResponse {
// estimate sha3x hash rate
uint64 sha3x_estimated_hash_rate = 6;
// estimate randomx hash rate
uint64 randomx_estimated_hash_rate = 7;
uint64 monero_randomx_estimated_hash_rate = 7;
uint64 tari_randomx_estimated_hash_rate = 10;
// number of connections
uint64 num_connections = 8;
//liveness results
repeated LivenessResult liveness_results = 9;
}
message LivenessResult{
// node id
bytes peer_node_id = 1;
// time to discover
uint64 discover_latency = 2;
// Dial latency
uint64 ping_latency = 3;
}
+21 -20
View File
@@ -371,22 +371,22 @@ const char descriptor_table_protodef_block_2eproto[] ABSL_ATTRIBUTE_SECTION_VARI
"tal_script_offset\030\017 \001(\014\022\031\n\021validator_nod"
"e_mr\030\020 \001(\014\022\033\n\023validator_node_size\030\021 \001(\004\""
"1\n\013ProofOfWork\022\020\n\010pow_algo\030\001 \001(\004\022\020\n\010pow_"
"data\030\004 \001(\014\"o\n\007PowAlgo\022,\n\010pow_algo\030\001 \001(\0162"
"\032.tari.rpc.PowAlgo.PowAlgos\"6\n\010PowAlgos\022"
"\025\n\021POW_ALGOS_RANDOMX\020\000\022\023\n\017POW_ALGOS_SHA3"
"X\020\001\"U\n\005Block\022%\n\006header\030\001 \001(\0132\025.tari.rpc."
"BlockHeader\022%\n\004body\030\002 \001(\0132\027.tari.rpc.Agg"
"regateBody\"H\n\017HistoricalBlock\022\025\n\rconfirm"
"ations\030\001 \001(\004\022\036\n\005block\030\002 \001(\0132\017.tari.rpc.B"
"lock\"\252\001\n\026NewBlockHeaderTemplate\022\017\n\007versi"
"on\030\001 \001(\r\022\016\n\006height\030\002 \001(\004\022\021\n\tprev_hash\030\003 "
"\001(\014\022\033\n\023total_kernel_offset\030\004 \001(\014\022\"\n\003pow\030"
"\005 \001(\0132\025.tari.rpc.ProofOfWork\022\033\n\023total_sc"
"ript_offset\030\007 \001(\014\"\207\001\n\020NewBlockTemplate\0220"
"\n\006header\030\001 \001(\0132 .tari.rpc.NewBlockHeader"
"Template\022%\n\004body\030\002 \001(\0132\027.tari.rpc.Aggreg"
"ateBody\022\032\n\022is_mempool_in_sync\030\003 \001(\010b\006pro"
"to3"
"data\030\004 \001(\014\"\210\001\n\007PowAlgo\022,\n\010pow_algo\030\001 \001(\016"
"2\032.tari.rpc.PowAlgo.PowAlgos\"O\n\010PowAlgos"
"\022\026\n\022POW_ALGOS_RANDOMXM\020\000\022\023\n\017POW_ALGOS_SH"
"A3X\020\001\022\026\n\022POW_ALGOS_RANDOMXT\020\002\"U\n\005Block\022%"
"\n\006header\030\001 \001(\0132\025.tari.rpc.BlockHeader\022%\n"
"\004body\030\002 \001(\0132\027.tari.rpc.AggregateBody\"H\n\017"
"HistoricalBlock\022\025\n\rconfirmations\030\001 \001(\004\022\036"
"\n\005block\030\002 \001(\0132\017.tari.rpc.Block\"\252\001\n\026NewBl"
"ockHeaderTemplate\022\017\n\007version\030\001 \001(\r\022\016\n\006he"
"ight\030\002 \001(\004\022\021\n\tprev_hash\030\003 \001(\014\022\033\n\023total_k"
"ernel_offset\030\004 \001(\014\022\"\n\003pow\030\005 \001(\0132\025.tari.r"
"pc.ProofOfWork\022\033\n\023total_script_offset\030\007 "
"\001(\014\"\207\001\n\020NewBlockTemplate\0220\n\006header\030\001 \001(\013"
"2 .tari.rpc.NewBlockHeaderTemplate\022%\n\004bo"
"dy\030\002 \001(\0132\027.tari.rpc.AggregateBody\022\032\n\022is_"
"mempool_in_sync\030\003 \001(\010b\006proto3"
};
static const ::_pbi::DescriptorTable* const descriptor_table_block_2eproto_deps[1] =
{
@@ -396,7 +396,7 @@ static ::absl::once_flag descriptor_table_block_2eproto_once;
const ::_pbi::DescriptorTable descriptor_table_block_2eproto = {
false,
false,
1083,
1109,
descriptor_table_protodef_block_2eproto,
"block.proto",
&descriptor_table_block_2eproto_once,
@@ -432,15 +432,16 @@ const ::google::protobuf::EnumDescriptor* PowAlgo_PowAlgos_descriptor() {
return file_level_enum_descriptors_block_2eproto[0];
}
PROTOBUF_CONSTINIT const uint32_t PowAlgo_PowAlgos_internal_data_[] = {
131072u, 0u, };
196608u, 0u, };
bool PowAlgo_PowAlgos_IsValid(int value) {
return 0 <= value && value <= 1;
return 0 <= value && value <= 2;
}
#if (__cplusplus < 201703) && \
(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
constexpr PowAlgo_PowAlgos PowAlgo::POW_ALGOS_RANDOMX;
constexpr PowAlgo_PowAlgos PowAlgo::POW_ALGOS_RANDOMXM;
constexpr PowAlgo_PowAlgos PowAlgo::POW_ALGOS_SHA3X;
constexpr PowAlgo_PowAlgos PowAlgo::POW_ALGOS_RANDOMXT;
constexpr PowAlgo_PowAlgos PowAlgo::PowAlgos_MIN;
constexpr PowAlgo_PowAlgos PowAlgo::PowAlgos_MAX;
constexpr int PowAlgo::PowAlgos_ARRAYSIZE;
+7 -5
View File
@@ -84,8 +84,9 @@ namespace protobuf {
namespace tari {
namespace rpc {
enum PowAlgo_PowAlgos : int {
PowAlgo_PowAlgos_POW_ALGOS_RANDOMX = 0,
PowAlgo_PowAlgos_POW_ALGOS_RANDOMXM = 0,
PowAlgo_PowAlgos_POW_ALGOS_SHA3X = 1,
PowAlgo_PowAlgos_POW_ALGOS_RANDOMXT = 2,
PowAlgo_PowAlgos_PowAlgo_PowAlgos_INT_MIN_SENTINEL_DO_NOT_USE_ =
std::numeric_limits<::int32_t>::min(),
PowAlgo_PowAlgos_PowAlgo_PowAlgos_INT_MAX_SENTINEL_DO_NOT_USE_ =
@@ -95,8 +96,8 @@ enum PowAlgo_PowAlgos : int {
bool PowAlgo_PowAlgos_IsValid(int value);
extern const uint32_t PowAlgo_PowAlgos_internal_data_[];
constexpr PowAlgo_PowAlgos PowAlgo_PowAlgos_PowAlgos_MIN = static_cast<PowAlgo_PowAlgos>(0);
constexpr PowAlgo_PowAlgos PowAlgo_PowAlgos_PowAlgos_MAX = static_cast<PowAlgo_PowAlgos>(1);
constexpr int PowAlgo_PowAlgos_PowAlgos_ARRAYSIZE = 1 + 1;
constexpr PowAlgo_PowAlgos PowAlgo_PowAlgos_PowAlgos_MAX = static_cast<PowAlgo_PowAlgos>(2);
constexpr int PowAlgo_PowAlgos_PowAlgos_ARRAYSIZE = 2 + 1;
const ::google::protobuf::EnumDescriptor*
PowAlgo_PowAlgos_descriptor();
template <typename T>
@@ -109,7 +110,7 @@ const std::string& PowAlgo_PowAlgos_Name(T value) {
template <>
inline const std::string& PowAlgo_PowAlgos_Name(PowAlgo_PowAlgos value) {
return ::google::protobuf::internal::NameOfDenseEnum<PowAlgo_PowAlgos_descriptor,
0, 1>(
0, 2>(
static_cast<int>(value));
}
inline bool PowAlgo_PowAlgos_Parse(absl::string_view name, PowAlgo_PowAlgos* value) {
@@ -430,8 +431,9 @@ class PowAlgo final : public ::google::protobuf::Message
::google::protobuf::Metadata GetMetadata() const final;
// nested types ----------------------------------------------------
using PowAlgos = PowAlgo_PowAlgos;
static constexpr PowAlgos POW_ALGOS_RANDOMX = PowAlgo_PowAlgos_POW_ALGOS_RANDOMX;
static constexpr PowAlgos POW_ALGOS_RANDOMXM = PowAlgo_PowAlgos_POW_ALGOS_RANDOMXM;
static constexpr PowAlgos POW_ALGOS_SHA3X = PowAlgo_PowAlgos_POW_ALGOS_SHA3X;
static constexpr PowAlgos POW_ALGOS_RANDOMXT = PowAlgo_PowAlgos_POW_ALGOS_RANDOMXT;
static inline bool PowAlgos_IsValid(int value) {
return PowAlgo_PowAlgos_IsValid(value);
}
+2 -1
View File
@@ -80,8 +80,9 @@ message ProofOfWork {
message PowAlgo {
// The permitted pow algorithms
enum PowAlgos {
POW_ALGOS_RANDOMX = 0; // Accessible as `grpc::pow_algo::PowAlgos::Randomx`
POW_ALGOS_RANDOMXM = 0; // Accessible as `grpc::pow_algo::PowAlgos::RandomxM`
POW_ALGOS_SHA3X = 1; // Accessible as `grpc::pow_algo::PowAlgos::Sha3x`
POW_ALGOS_RANDOMXT = 2; // Accessible as `grpc::pow_algo::PowAlgos::RandomxT`
}
// The pow algo to use
PowAlgos pow_algo = 1;
+11 -3
View File
@@ -21,6 +21,14 @@
#include <memory.h>
/****************************** MACROS ******************************/
typedef struct {
uint8_t data[64];
uint32_t datalen;
uint32_t padding;
uint64_t bitlen;
uint32_t state[8];
} SHA256_CTX;
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
@@ -85,7 +93,7 @@ static void sha256_transform(SHA256_CTX *ctx, const uint8_t* data)
ctx->state[7] += h;
}
void sha256_init(SHA256_CTX *ctx)
static void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
@@ -99,7 +107,7 @@ void sha256_init(SHA256_CTX *ctx)
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(SHA256_CTX *ctx, const uint8_t* data, uint32_t len)
static void sha256_update(SHA256_CTX *ctx, const uint8_t* data, uint32_t len)
{
uint32_t i;
@@ -114,7 +122,7 @@ void sha256_update(SHA256_CTX *ctx, const uint8_t* data, uint32_t len)
}
}
void sha256_final(SHA256_CTX *ctx, uint8_t* hash)
static void sha256_final(SHA256_CTX *ctx, uint8_t* hash)
{
uint32_t i;
-16
View File
@@ -16,22 +16,6 @@ extern "C" {
/*************************** HEADER FILES ***************************/
#include <stdint.h>
/****************************** MACROS ******************************/
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
typedef struct {
uint8_t data[64];
uint32_t datalen;
uint32_t padding;
uint64_t bitlen;
uint32_t state[8];
} SHA256_CTX;
/*********************** FUNCTION DECLARATIONS **********************/
void sha256_init(SHA256_CTX *ctx);
void sha256_update(SHA256_CTX *ctx, const uint8_t* data, uint32_t len);
void sha256_final(SHA256_CTX *ctx, uint8_t* hash);
void sha256(const void* data, uint32_t len, uint8_t* hash);
#ifdef __cplusplus
+14
View File
@@ -612,6 +612,20 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
m_poolBlockTemplate->m_auxChains = data.aux_chains;
m_poolBlockTemplate->m_auxNonce = data.aux_nonce;
m_poolBlockTemplate->m_mergeMiningExtra.clear();
for (const AuxChainData& c : data.aux_chains) {
std::vector<uint8_t> v;
v.reserve(HASH_SIZE + 16);
v.assign(c.data.h, c.data.h + HASH_SIZE);
writeVarint(c.difficulty.lo, v);
writeVarint(c.difficulty.hi, v);
m_poolBlockTemplate->m_mergeMiningExtra.emplace(c.unique_id, std::move(v));
}
init_merge_mining_merkle_proof();
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
+3 -1
View File
@@ -111,8 +111,10 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
(void)ssl_fingerprint;
#endif
const bool is_v6 = (address.find(':') != std::string::npos);
log::Stream s(buf);
s << protocol << address << ':' << port;
s << protocol << (is_v6 ? "[" : "") << address << (is_v6 ? "]:" : ":") << port;
if (!m_req.empty() && (m_req.front() == '/')) {
s << m_req.c_str() << '\0';
+3
View File
@@ -62,6 +62,7 @@ void p2pool_usage()
"--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 450)\n"
"--start-mining N Start built-in miner using N threads (any value between 1 and 64)\n"
"--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from %d to %d\n"
"--nano Connect to p2pool-nano sidechain. Note that it will also change default p2p port from %d to %d\n"
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (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"
@@ -88,6 +89,8 @@ void p2pool_usage()
p2pool::log::MAX_GLOBAL_LOG_LEVEL,
p2pool::DEFAULT_P2P_PORT,
p2pool::DEFAULT_P2P_PORT_MINI,
p2pool::DEFAULT_P2P_PORT,
p2pool::DEFAULT_P2P_PORT_NANO,
#ifdef _WIN32
"p2pool.exe"
#else
+3 -1
View File
@@ -21,6 +21,7 @@ namespace p2pool {
class p2pool;
class BlockTemplate;
struct PoolBlock;
class IMergeMiningClient
{
@@ -38,7 +39,8 @@ public:
virtual ~IMergeMiningClient() {}
[[nodiscard]] virtual bool get_params(ChainParameters& out_params) const = 0;
virtual void submit_solution(const BlockTemplate* block_tpl, 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 on_external_block(const PoolBlock& block) = 0;
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;
};
+1 -1
View File
@@ -287,7 +287,7 @@ bool MergeMiningClientJSON_RPC::parse_merge_mining_get_aux_block(const char* dat
return true;
}
void MergeMiningClientJSON_RPC::submit_solution(const BlockTemplate* /*block_tpl*/, 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)
void MergeMiningClientJSON_RPC::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)
{
ReadLock lock(m_lock);
+3 -1
View File
@@ -22,6 +22,7 @@
namespace p2pool {
class p2pool;
struct PoolBlock;
class MergeMiningClientJSON_RPC : public IMergeMiningClient
{
@@ -30,7 +31,8 @@ public:
~MergeMiningClientJSON_RPC() override;
bool get_params(ChainParameters& out_params) const override;
void submit_solution(const BlockTemplate* block_tpl, 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 on_external_block(const PoolBlock& /*block*/) override {}
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;
+344 -91
View File
@@ -22,6 +22,9 @@
#include "params.h"
#include "block_template.h"
#include "keccak.h"
#include "pool_block.h"
#include "merkle.h"
#include "side_chain.h"
LOG_CATEGORY(MergeMiningClientTari)
@@ -31,6 +34,8 @@ namespace p2pool {
MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, const std::string& wallet)
: m_chainParams{}
, m_previousAuxHashes{}
, m_previousAuxHashesIndex(0)
, m_auxWallet(wallet)
, m_pool(pool)
, m_tariJobParams{}
@@ -79,7 +84,17 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
log::Stream s(buf);
s << "127.0.0.1:" << m_server->external_listen_port();
m_TariNode = new BaseNode::Stub(grpc::CreateChannel(buf, grpc::InsecureChannelCredentials()));
grpc::ChannelArguments cArgs;
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);
cArgs.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, -1);
cArgs.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, -1);
m_TariNode = new BaseNode::Stub(grpc::CreateCustomChannel(buf, grpc::InsecureChannelCredentials(), cArgs));
uv_mutex_init_checked(&m_workerLock);
uv_cond_init_checked(&m_workerCond);
@@ -127,7 +142,191 @@ bool MergeMiningClientTari::get_params(ChainParameters& out_params) const
return true;
}
void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, 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)
void MergeMiningClientTari::on_external_block(const PoolBlock& block)
{
#ifdef WITH_MERGE_MINING_DONATION
// The rest of the code is needed only when this node is sending donation messages
if (m_pool->params().m_authorKeyFile.empty()) {
return;
}
// Sanity check
if (block.m_transactions.empty() || block.m_hashingBlob.empty() || (block.m_hashingBlob.size() > 128)) {
LOGWARN(3, "on_external_block: sanity check failed - " << block.m_transactions.size() << " transactions, hashing blob size = " << block.m_hashingBlob.size());
return;
}
ChainParameters chain_params;
uint64_t previous_aux_hashes[NUM_PREVIOUS_HASHES];
{
ReadLock lock(m_chainParamsLock);
chain_params = m_chainParams;
memcpy(previous_aux_hashes, m_previousAuxHashes, sizeof(m_previousAuxHashes));
}
// Don't continue if our aux chain is not there
if (block.m_mergeMiningExtra.find(chain_params.aux_id) == block.m_mergeMiningExtra.end()) {
return;
}
std::vector<hash> aux_ids;
std::vector<AuxChainData> aux_chains;
// All aux chains in this block + the P2Pool sidechain
aux_ids.reserve(block.m_mergeMiningExtra.size() + 1);
// All aux chains in this block
aux_chains.reserve(block.m_mergeMiningExtra.size());
for (const auto& i : block.m_mergeMiningExtra) {
const std::vector<uint8_t>& v = i.second;
const uint8_t* p = v.data();
const uint8_t* e = v.data() + v.size();
if (p + HASH_SIZE > e) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '1');
return;
}
hash data;
memcpy(data.h, p, HASH_SIZE);
p += HASH_SIZE;
difficulty_type diff;
p = readVarint(p, e, diff.lo);
if (!p) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '2');
return;
}
p = readVarint(p, e, diff.hi);
if (!p) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '3');
return;
}
// If it's our aux chain, check that it's the same job and that there is enough PoW
if (i.first == chain_params.aux_id) {
if ((data != chain_params.aux_hash) || (diff != chain_params.aux_diff)) {
const uint64_t* a = previous_aux_hashes;
const uint64_t* b = previous_aux_hashes + NUM_PREVIOUS_HASHES;
if (std::find(a, b, *data.u64()) == b) {
LOGINFO(4, "External aux job solution found, but it's for another miner");
return;
}
else {
LOGINFO(4, "External aux job solution found, but it's stale");
}
}
if (!diff.check_pow(block.m_powHash)) {
LOGINFO(4, "External aux job solution found, but it doesn't have enough PoW (block diff = " << block.m_difficulty << ", Tari diff = " << diff << ')');
return;
}
}
aux_ids.emplace_back(i.first);
aux_chains.emplace_back(i.first, data, diff);
}
aux_ids.emplace_back(m_pool->side_chain().consensus_hash());
LOGINFO(0, log::LightGreen() << "External aux job solution found. Processing it!");
// coinbase_merkle_proof
std::vector<std::vector<hash>> tree;
merkle_hash_full_tree(block.m_transactions, tree);
std::vector<hash> proof;
uint32_t path;
if (!get_merkle_proof(tree, block.m_transactions[0], proof, path)) {
LOGWARN(3, "on_external_block: get_merkle_proof failed for coinbase transaction");
return;
}
std::vector<uint8_t> coinbase_merkle_proof;
for (const hash& h : proof) {
coinbase_merkle_proof.insert(coinbase_merkle_proof.end(), h.h, h.h + HASH_SIZE);
}
// hashing_blob
uint8_t hashing_blob[128] = {};
memcpy(hashing_blob, block.m_hashingBlob.data(), block.m_hashingBlob.size());
// nonce_offset and blob
size_t header_size = 0;
const std::vector<uint8_t> blob = block.serialize_mainchain_data(&header_size);
if (header_size <= NONCE_SIZE) {
LOGWARN(3, "on_external_block: invalid header_size");
return;
}
const uint32_t nonce_offset = static_cast<uint32_t>(header_size - NONCE_SIZE);
// aux_merkle_proof, aux_merkle_proof_path
std::vector<hash> aux_merkle_proof;
uint32_t aux_merkle_proof_path = 0;
const hash sidechain_id = block.m_sidechainId;
const uint32_t n_aux_chains = static_cast<uint32_t>(block.m_mergeMiningExtra.size() + 1);
std::vector<hash> hashes(n_aux_chains);
uint32_t aux_nonce;
if (!find_aux_nonce(aux_ids, aux_nonce, 1000)) {
LOGWARN(3, "on_external_block: failed to find aux_nonce");
return;
}
for (const AuxChainData& aux_data : aux_chains) {
const uint32_t aux_slot = get_aux_slot(aux_data.unique_id, aux_nonce, n_aux_chains);
if (!hashes[aux_slot].empty()) {
LOGWARN(3, "on_external_block: found an incorrect aux_nonce " << '1');
return;
}
hashes[aux_slot] = aux_data.data;
}
const uint32_t aux_slot = get_aux_slot(m_pool->side_chain().consensus_hash(), aux_nonce, n_aux_chains);
if (!hashes[aux_slot].empty()) {
LOGWARN(3, "on_external_block: found an incorrect aux_nonce " << '2');
return;
}
hashes[aux_slot] = sidechain_id;
merkle_hash_full_tree(hashes, tree);
if (tree.empty() || tree.back().empty() || (tree.back().front() != block.m_merkleRoot)) {
LOGWARN(3, "on_external_block: merkle root didn't match");
return;
}
if (!get_merkle_proof(tree, chain_params.aux_hash, aux_merkle_proof, aux_merkle_proof_path)) {
LOGWARN(3, "on_external_block: get_merkle_proof failed for the aux hash");
return;
}
submit_solution(coinbase_merkle_proof, hashing_blob, nonce_offset, block.m_seed, blob, aux_merkle_proof, aux_merkle_proof_path);
#else // WITH_MERGE_MINING_DONATION
(void) block;
#endif // WITH_MERGE_MINING_DONATION
}
void MergeMiningClientTari::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)
{
Block block;
{
@@ -136,7 +335,7 @@ void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, cons
}
ProofOfWork* pow = block.mutable_header()->mutable_pow();
pow->set_pow_algo(PowAlgo_PowAlgos_POW_ALGOS_RANDOMX);
pow->set_pow_algo(PowAlgo_PowAlgos_POW_ALGOS_RANDOMXM);
{
std::string data;
@@ -164,8 +363,6 @@ void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, cons
data.append(reinterpret_cast<const char*>(hashing_blob + nonce_offset + sizeof(uint32_t)), HASH_SIZE);
// Coinbase transaction's Merkle proof
const std::vector<uint8_t> coinbase_merkle_proof = block_tpl->get_coinbase_merkle_proof();
// Number of hashes in the proof (varint, but an O(logN) proof will never get bigger than 127)
data.append(1, static_cast<char>(coinbase_merkle_proof.size() / HASH_SIZE));
@@ -247,7 +444,35 @@ void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, cons
uv_work_t req;
MergeMiningClientTari* client;
Block block;
} *work = new Work{ {}, this, std::move(block) };
FORCEINLINE Work(MergeMiningClientTari* c, Block&& b) : req{}, client(c), block(std::move(b)) {}
void process() const
{
grpc::ClientContext ctx;
SubmitBlockResponse response;
const grpc::Status status = client->m_TariNode->SubmitBlock(&ctx, block, &response);
if (!status.ok()) {
LOGWARN(4, "SubmitBlock failed: " << status.error_message());
if (!status.error_details().empty()) {
LOGWARN(4, "SubmitBlock failed: " << status.error_details());
}
}
else {
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());
}
}
} *work = new Work(this, std::move(block));
if (!is_main_thread()) {
LOGINFO(5, "Running SubmitBlock in the current thread because uv_default_loop can only be used in the main thread");
work->process();
delete work;
return;
}
work->req.data = work;
@@ -255,23 +480,7 @@ void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, cons
[](uv_work_t* req)
{
BACKGROUND_JOB_START(MergeMiningClientTari::submit_solution);
grpc::ClientContext ctx;
SubmitBlockResponse response;
const Work* w = reinterpret_cast<Work*>(req->data);
const grpc::Status status = w->client->m_TariNode->SubmitBlock(&ctx, w->block, &response);
if (!status.ok()) {
LOGWARN(5, "SubmitBlock failed: " << status.error_message());
if (!status.error_details().empty()) {
LOGWARN(5, "SubmitBlock failed: " << status.error_details());
}
}
else {
const std::string& h = response.block_hash();
LOGINFO(0, log::LightGreen() << "Mined Tari block " << log::hex_buf(h.data(), h.size()) << " at height " << w->block.header().height());
}
reinterpret_cast<Work*>(req->data)->process();
},
[](uv_work_t* req, int /*status*/)
{
@@ -338,98 +547,142 @@ void MergeMiningClientTari::run()
using namespace std::chrono;
TipInfoResponse prev_tip_info{};
auto prev_tip_info_update_time = high_resolution_clock::now();
auto same_tip = [](const TipInfoResponse& a, const TipInfoResponse& b) -> bool {
return
(a.metadata().best_block_height() == b.metadata().best_block_height()) &&
(a.metadata().best_block_hash() == b.metadata().best_block_hash()) &&
(a.metadata().accumulated_difficulty() == b.metadata().accumulated_difficulty()) &&
(a.initial_sync_achieved() == b.initial_sync_achieved()) &&
(a.base_node_state() == b.base_node_state()) &&
(a.failed_checkpoints() == b.failed_checkpoints());
};
for (;;) {
const auto t1 = high_resolution_clock::now();
const auto start_time = high_resolution_clock::now();
// Force frequent enough updates (at least every 30 seconds)
if (duration_cast<seconds>(start_time - prev_tip_info_update_time).count() >= 30) {
prev_tip_info.mutable_metadata()->set_best_block_height(0);
}
MutexLock lock(m_workerLock);
GetNewBlockTemplateWithCoinbasesRequest request;
PowAlgo* algo = new PowAlgo();
algo->set_pow_algo(PowAlgo_PowAlgos_POW_ALGOS_RANDOMX);
request.clear_algo();
request.set_allocated_algo(algo);
request.set_max_weight(0);
grpc::ClientContext get_tip_info_ctx{};
Empty get_tip_info_request{};
TipInfoResponse cur_tip_info{};
NewBlockCoinbase* coinbase = request.add_coinbases();
coinbase->set_address(m_auxWallet);
const grpc::Status get_tip_info_status = m_TariNode->GetTipInfo(&get_tip_info_ctx, get_tip_info_request, &cur_tip_info);
// TODO this should be equal to the total weight of shares in the PPLNS window for each wallet
coinbase->set_value(1);
coinbase->set_stealth_payment(false);
coinbase->set_revealed_value_proof(true);
coinbase->clear_coinbase_extra();
grpc::ClientContext ctx;
GetNewBlockResult response;
const grpc::Status status = m_TariNode->GetNewBlockTemplateWithCoinbases(&ctx, request, &response);
if (!status.ok()) {
LOGWARN(5, "GetNewBlockTemplateWithCoinbases failed: " << status.error_message());
if (!status.error_details().empty()) {
LOGWARN(5, "GetNewBlockTemplateWithCoinbases failed: " << status.error_details());
if (!get_tip_info_status.ok()) {
LOGWARN(4, "GetTipInfo failed: " << get_tip_info_status.error_message());
if (!get_tip_info_status.error_details().empty()) {
LOGWARN(4, "GetTipInfo failed: " << get_tip_info_status.error_details());
}
}
else {
const std::string& id = response.tari_unique_id();
const std::string& mm_hash = response.merge_mining_hash();
else if (!same_tip(cur_tip_info, prev_tip_info)) {
GetNewBlockTemplateWithCoinbasesRequest request{};
bool ok = true;
PowAlgo* algo = new PowAlgo();
algo->set_pow_algo(PowAlgo_PowAlgos_POW_ALGOS_RANDOMXM);
if (id.size() != HASH_SIZE) {
LOGERR(1, "Tari unique_id has invalid size (" << id.size() << ')');
ok = false;
request.clear_algo();
request.set_allocated_algo(algo);
request.set_max_weight(0);
NewBlockCoinbase* coinbase = request.add_coinbases();
coinbase->set_address(m_auxWallet);
// TODO this should be equal to the total weight of shares in the PPLNS window for each wallet
coinbase->set_value(1);
coinbase->set_stealth_payment(false);
coinbase->set_revealed_value_proof(true);
coinbase->clear_coinbase_extra();
grpc::ClientContext ctx{};
GetNewBlockResult response{};
const grpc::Status status = m_TariNode->GetNewBlockTemplateWithCoinbases(&ctx, request, &response);
if (!status.ok()) {
LOGWARN(4, "GetNewBlockTemplateWithCoinbases failed: " << status.error_message());
if (!status.error_details().empty()) {
LOGWARN(4, "GetNewBlockTemplateWithCoinbases failed: " << status.error_details());
}
}
else {
prev_tip_info = cur_tip_info;
prev_tip_info_update_time = start_time;
if (mm_hash.size() != HASH_SIZE) {
LOGERR(1, "Tari merge mining hash has invalid size (" << mm_hash.size() << ')');
ok = false;
}
const std::string& id = response.tari_unique_id();
const std::string& mm_hash = response.merge_mining_hash();
if (ok) {
TariJobParams job_params;
bool ok = true;
job_params.height = response.block().header().height();
job_params.diff = response.miner_data().target_difficulty();
job_params.reward = response.miner_data().reward();
job_params.fees = response.miner_data().total_fees();
if (id.size() != HASH_SIZE) {
LOGERR(1, "Tari unique_id has invalid size (" << id.size() << ')');
ok = false;
}
hash chain_id;
{
WriteLock lock2(m_chainParamsLock);
if (mm_hash.size() != HASH_SIZE) {
LOGERR(1, "Tari merge mining hash has invalid size (" << mm_hash.size() << ')');
ok = false;
}
if (job_params != m_tariJobParams) {
m_tariJobParams = job_params;
if (ok) {
TariJobParams job_params;
if (m_chainParams.aux_id.empty()) {
LOGINFO(1, m_hostStr << " uses chain_id " << log::LightCyan() << log::hex_buf(id.data(), id.size()));
std::copy(id.begin(), id.end(), m_chainParams.aux_id.h);
job_params.height = response.block().header().height();
job_params.diff = response.miner_data().target_difficulty();
job_params.reward = response.miner_data().reward();
job_params.fees = response.miner_data().total_fees();
hash chain_id;
do {
WriteLock lock2(m_chainParamsLock);
if (job_params != m_tariJobParams) {
m_tariJobParams = job_params;
if (m_chainParams.aux_id.empty()) {
LOGINFO(1, m_hostStr << " uses chain_id " << log::LightCyan() << log::hex_buf(id.data(), id.size()));
std::copy(id.begin(), id.end(), m_chainParams.aux_id.h);
}
chain_id = m_chainParams.aux_id;
m_previousAuxHashes[(m_previousAuxHashesIndex++) % NUM_PREVIOUS_HASHES] = *m_chainParams.aux_hash.u64();
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_tariBlock = response.block();
LOGINFO(4, "Tari aux block template: height = " << job_params.height
<< ", diff = " << job_params.diff
<< ", reward = " << job_params.reward
<< ", fees = " << job_params.fees
<< ", hash = " << log::hex_buf(mm_hash.data(), mm_hash.size())
);
}
} while (0);
chain_id = m_chainParams.aux_id;
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_tariBlock = response.block();
LOGINFO(5, "Tari block template: height = " << job_params.height
<< ", diff = " << job_params.diff
<< ", reward = " << job_params.reward
<< ", fees = " << job_params.fees
<< ", hash = " << log::hex_buf(mm_hash.data(), mm_hash.size())
);
if (!chain_id.empty()) {
m_pool->update_aux_data(chain_id);
}
}
if (!chain_id.empty()) {
m_pool->update_aux_data(chain_id);
}
}
}
const int64_t timeout = std::max<int64_t>(500'000'000 - duration_cast<nanoseconds>(high_resolution_clock::now() - t1).count(), 1'000'000);
auto dt = duration_cast<nanoseconds>(high_resolution_clock::now() - start_time).count();
LOGINFO(6, "Polling loop took " << (static_cast<double>(dt) * 1e-6) << " ms");
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;
+11 -1
View File
@@ -23,6 +23,7 @@
namespace p2pool {
class p2pool;
struct PoolBlock;
class MergeMiningClientTari : public IMergeMiningClient, public nocopy_nomove
{
@@ -33,13 +34,22 @@ public:
static constexpr char TARI_PREFIX[] = "tari://";
bool get_params(ChainParameters& out_params) const override;
void submit_solution(const BlockTemplate* block_tpl, 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 on_external_block(const PoolBlock& block) override;
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;
private:
mutable uv_rwlock_t m_chainParamsLock;
ChainParameters m_chainParams;
enum {
NUM_PREVIOUS_HASHES = 8,
};
uint64_t m_previousAuxHashes[NUM_PREVIOUS_HASHES];
uint32_t m_previousAuxHashesIndex;
tari::rpc::Block m_tariBlock;
std::string m_auxWallet;
+310 -2
View File
@@ -29,6 +29,16 @@
#include "p2pool_api.h"
#include "stratum_server.h"
#include "rapidjson_wrapper.h"
#include "merge_mining_client.h"
#include "sha256.h"
#ifdef WITH_TLS
#include <openssl/curve25519.h>
#else
#define ED25519_PUBLIC_KEY_LEN 32
#define ED25519_SIGNATURE_LEN 64
#endif
#include <fstream>
#include <numeric>
@@ -37,6 +47,7 @@ LOG_CATEGORY(P2PServer)
static constexpr char saved_peer_list_file_name[] = "p2pool_peers.txt";
static const char* seed_nodes[] = { "seeds.p2pool.io", "main.p2poolpeers.net", "main.gupax.io", "" };
static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "mini.p2poolpeers.net", "mini.gupax.io", "" };
static const char* seed_nodes_nano[] = { "seeds-nano.p2pool.io", "nano.p2poolpeers.net", "nano.gupax.io", ""};
static constexpr int DEFAULT_BACKLOG = 16;
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
@@ -62,10 +73,13 @@ P2PServer::P2PServer(p2pool* pool)
, m_lookForMissingBlocks(true)
, m_fastestPeer(nullptr)
, m_newP2PoolVersionDetected(false)
, m_auxJobLastMessageTimestamp(0)
{
m_callbackBuf.resize(P2P_BUF_SIZE);
m_blockDeserializeBuf.reserve(MAX_BLOCK_SIZE);
m_auxJobMessages.reserve(1024);
// Diffuse the initial state in case it has low quality
m_rng.discard(10000);
@@ -105,6 +119,17 @@ P2PServer::P2PServer(p2pool* pool)
}
m_showPeersAsync.data = this;
#ifdef WITH_MERGE_MINING_DONATION
uv_mutex_init_checked(&m_AuxJobBroadcastLock);
err = uv_async_init(&m_loop, &m_AuxJobBroadcastAsync, on_aux_job_broadcast);
if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
PANIC_STOP();
}
m_AuxJobBroadcastAsync.data = this;
#endif
err = uv_timer_init(&m_loop, &m_timer);
if (err) {
LOGERR(1, "failed to create timer, error " << uv_err_name(err));
@@ -142,6 +167,10 @@ P2PServer::~P2PServer()
uv_mutex_destroy(&m_connectToPeersLock);
uv_mutex_destroy(&m_showPeersLock);
#ifdef WITH_MERGE_MINING_DONATION
uv_mutex_destroy(&m_AuxJobBroadcastLock);
#endif
delete m_block;
delete m_cache;
@@ -578,6 +607,9 @@ void P2PServer::load_peer_list()
else if (m_pool->side_chain().is_mini()) {
load_from_seed_nodes(seed_nodes_mini, DEFAULT_P2P_PORT_MINI);
}
else if (m_pool->side_chain().is_nano()) {
load_from_seed_nodes(seed_nodes_nano, DEFAULT_P2P_PORT_NANO);
}
}
// Finally load peers from p2pool_peers.txt
@@ -670,7 +702,7 @@ void P2PServer::load_monerod_peer_list()
#undef ERR_STR
const int port = m_pool->side_chain().is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT;
const int port = m_pool->side_chain().is_mini() ? DEFAULT_P2P_PORT_MINI : (m_pool->side_chain().is_nano() ? DEFAULT_P2P_PORT_NANO : DEFAULT_P2P_PORT);
const SizeType n = white_list.Size();
@@ -1008,7 +1040,7 @@ void P2PServer::on_broadcast()
return p - buf;
});
if (!result) {
LOGWARN(5, "failed to broadcast to " << static_cast<char*>(client->m_addrString) << ", disconnecting");
LOGWARN(5, "failed to broadcast a block to " << static_cast<char*>(client->m_addrString) << ", disconnecting");
client->close();
break;
}
@@ -1061,6 +1093,15 @@ void P2PServer::show_peers() const
if (client->m_SoftwareVersion) {
log::Stream s(buf);
s << P2PClient::SoftwareDisplayName(client->m_SoftwareID, client->m_SoftwareVersion);
// Show protocol version in peer list
switch (client->m_protocolVersion) {
case PROTOCOL_VERSION_1_0: s << " p1.0"; break;
case PROTOCOL_VERSION_1_1: s << " p1.1"; break;
case PROTOCOL_VERSION_1_2: s << " p1.2"; break;
case PROTOCOL_VERSION_1_3: s << " p1.3"; break;
default: s << " p?"; break;
}
}
LOGINFO(0, (client->m_isIncoming ? "I\t" : "O\t")
<< log::pad_right(log::Duration(cur_time - client->m_connectedTime), 16) << '\t'
@@ -1132,6 +1173,7 @@ void P2PServer::on_timer()
check_block_template();
check_for_updates();
api_update_local_stats();
clean_aux_job_messages();
}
void P2PServer::flush_cache()
@@ -1374,6 +1416,13 @@ void P2PServer::on_shutdown()
MutexLock lock(m_showPeersLock);
uv_close(reinterpret_cast<uv_handle_t*>(&m_showPeersAsync), nullptr);
}
#ifdef WITH_MERGE_MINING_DONATION
{
MutexLock lock(m_AuxJobBroadcastLock);
uv_close(reinterpret_cast<uv_handle_t*>(&m_AuxJobBroadcastAsync), nullptr);
}
#endif
}
void P2PServer::api_update_local_stats()
@@ -1429,6 +1478,112 @@ void P2PServer::api_update_local_stats()
});
}
#ifdef WITH_MERGE_MINING_DONATION
void P2PServer::broadcast_aux_job_donation_async(const uint8_t* data, uint32_t data_size, uint64_t timestamp)
{
MutexLock lock(m_AuxJobBroadcastLock);
m_AuxJobBroadcast.job.assign(data, data + data_size);
m_AuxJobBroadcast.timestamp = timestamp;
const int err = uv_async_send(&m_AuxJobBroadcastAsync);
if (err) {
LOGERR(1, "uv_async_send failed, error " << uv_err_name(err));
}
}
void P2PServer::broadcast_aux_job_donation_handler()
{
AuxJobBroadcast auxJobBroadcast;
{
MutexLock lock(m_AuxJobBroadcastLock);
auxJobBroadcast = std::move(m_AuxJobBroadcast);
}
if (auxJobBroadcast.job.empty()) {
return;
}
broadcast_aux_job_donation(auxJobBroadcast.job.data(), static_cast<uint32_t>(auxJobBroadcast.job.size()), auxJobBroadcast.timestamp, nullptr, false);
}
#endif
void P2PServer::broadcast_aux_job_donation(const uint8_t* data, uint32_t data_size, uint64_t timestamp, const P2PClient* source, bool duplicate_check_done)
{
check_event_loop_thread(__func__);
if (!duplicate_check_done) {
hash digest;
sha256(data, data_size, digest.h);
// Every message can be received from multiple peers, so broadcast it only once
if (!m_auxJobMessages.emplace(*digest.u64(), timestamp).second) {
return;
}
}
m_auxJobLastMessage.assign(data, data + data_size);
m_auxJobLastMessageTimestamp = timestamp;
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
if ((source && (client == source)) || !client->is_good() || (client->m_protocolVersion < PROTOCOL_VERSION_1_3)) {
continue;
}
send_aux_job_donation(client, data, data_size);
}
}
void P2PServer::send_aux_job_donation(P2PServer::P2PClient* client, const uint8_t* data, uint32_t data_size)
{
const bool result = send(client, [client, data, data_size](uint8_t* buf, size_t buf_size) -> size_t {
LOGINFO(6, "sending AUX_JOB_DONATION to " << static_cast<char*>(client->m_addrString));
if (buf_size < 1 + sizeof(uint32_t) + data_size) {
return 0;
}
uint8_t* p = buf;
*(p++) = static_cast<uint8_t>(MessageId::AUX_JOB_DONATION);
memcpy(p, &data_size, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, data, data_size);
p += data_size;
return p - buf;
});
if (!result) {
LOGWARN(5, "failed to send AUX_JOB_DONATION to " << static_cast<char*>(client->m_addrString) << ", disconnecting");
client->close();
}
}
void P2PServer::clean_aux_job_messages()
{
if ((m_timerCounter & 255) != 0) {
return;
}
if (m_auxJobMessages.empty()) {
return;
}
const uint64_t cur_time = time(nullptr);
for (auto it = m_auxJobMessages.begin(); it != m_auxJobMessages.end();) {
// Delete old messages only after 3x the timeout to give some leeway for system clock adjustments
if (cur_time > it->second + AUX_JOB_TIMEOUT * 3) {
it = m_auxJobMessages.erase(it);
}
else {
++it;
}
}
}
P2PServer::P2PClient::~P2PClient()
{
}
@@ -1725,6 +1880,23 @@ bool P2PServer::P2PClient::on_read(const char* data, uint32_t size)
on_block_notify(buf + 1);
}
break;
case MessageId::AUX_JOB_DONATION:
LOGINFO(6, "peer " << log::Gray() << static_cast<char*>(m_addrString) << log::NoColor() << " sent AUX_JOB_DONATION");
if (bytes_left >= 1 + sizeof(uint32_t)) {
const uint32_t msg_size = read_unaligned(reinterpret_cast<uint32_t*>(buf + 1));
if (bytes_left >= 1 + sizeof(uint32_t) + msg_size) {
bytes_read = 1 + sizeof(uint32_t) + msg_size;
if (!on_aux_job_donation(buf + 1 + sizeof(uint32_t), msg_size)) {
ban(DEFAULT_BAN_TIME);
server->remove_peer_from_list(this);
return false;
}
}
}
break;
}
if (bytes_read) {
@@ -2432,6 +2604,13 @@ void P2PServer::P2PClient::on_peer_list_response(const uint8_t* buf)
<< "runs an unknown software with id = " << log::Hex(id_value)
);
}
// We know this peer's protocol version now. Send protocol-specific messages here.
if ((m_protocolVersion >= PROTOCOL_VERSION_1_3) && !server->m_auxJobLastMessage.empty()) {
if (static_cast<uint64_t>(time(nullptr)) < server->m_auxJobLastMessageTimestamp + AUX_JOB_TIMEOUT) {
server->send_aux_job_donation(this, server->m_auxJobLastMessage.data(), static_cast<uint32_t>(server->m_auxJobLastMessage.size()));
}
}
}
continue;
}
@@ -2510,6 +2689,135 @@ void P2PServer::P2PClient::on_block_notify(const uint8_t* buf)
}
}
bool P2PServer::P2PClient::on_aux_job_donation(const uint8_t* buf, uint32_t size)
{
P2PServer* server = static_cast<P2PServer*>(m_owner);
// Ignore the same message coming from other peers
if ((server->m_auxJobLastMessage.size() == size) && (memcmp(server->m_auxJobLastMessage.data(), buf, size) == 0)) {
return true;
}
const time_t cur_time = time(nullptr);
// Layout of the message:
//
// 32 bytes | Secondary public key
// 8 bytes | Secondary public key's expiration timestamp
// 64 bytes | Master key signature signing the above 40 bytes
// (size - 168) bytes | Data
// 64 bytes | Secondary key signature signing the data
constexpr uint32_t DATA_OFFSET = ED25519_PUBLIC_KEY_LEN + 8 + ED25519_SIGNATURE_LEN;
constexpr uint32_t OVERHEAD = DATA_OFFSET + ED25519_SIGNATURE_LEN;
constexpr uint32_t DATA_ENTRY_SIZE = HASH_SIZE * 2 + sizeof(difficulty_type);
constexpr uint32_t MIN_DATA_SIZE = sizeof(uint64_t) + DATA_ENTRY_SIZE;
// Ignore invalid or empty messages
if (size < OVERHEAD + MIN_DATA_SIZE) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an invalid AUX_JOB_DONATION message (" << size << " < " << (OVERHEAD + MIN_DATA_SIZE) << ')');
return false;
}
// Layout of the data:
//
// 8 bytes | timestamp
//
// Next come one or multiple data entries:
//
// 32 bytes | aux_id
// 32 bytes | aux_hash
// 16 bytes | aux_diff
const uint32_t data_size = size - OVERHEAD;
const int64_t secondary_key_expiration_time = read_unaligned(reinterpret_cast<const int64_t*>(buf + ED25519_PUBLIC_KEY_LEN));
// Ignore messages signed with an outdated secondary key
if (cur_time >= secondary_key_expiration_time) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an AUX_JOB_DONATION message with an expired secondary key (" << cur_time << " >= " << secondary_key_expiration_time << ")");
return true;
}
// Check secondary public key's signature
uint8_t signature[ED25519_SIGNATURE_LEN];
memcpy(signature, buf + ED25519_PUBLIC_KEY_LEN + 8, sizeof(signature));
// Ignore messages with invalid signatures
#ifdef WITH_TLS // Need BoringSSL to verify signatures
if (!ED25519_verify(buf, ED25519_PUBLIC_KEY_LEN + 8, signature, ED25519_MASTER_PUBLIC_KEY)) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an AUX_JOB_DONATION message with an invalid master key signature");
return true;
}
#endif
const uint8_t* p = buf + DATA_OFFSET;
const uint8_t* data_end = p + data_size;
memcpy(signature, data_end, sizeof(signature));
uint8_t secondary_public_key[ED25519_PUBLIC_KEY_LEN];
memcpy(secondary_public_key, buf, sizeof(secondary_public_key));
// Ignore messages with invalid signatures
#ifdef WITH_TLS // Need BoringSSL to verify signatures
if (!ED25519_verify(p, data_size, signature, secondary_public_key)) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an AUX_JOB_DONATION message with an invalid secondary key signature");
return true;
}
#endif
const int64_t data_timestamp = read_unaligned(reinterpret_cast<const int64_t*>(p));
p += sizeof(int64_t);
// Ignore outdated messages
if (cur_time >= data_timestamp + AUX_JOB_TIMEOUT) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an outdated AUX_JOB_DONATION message (" << cur_time << " >= " << data_timestamp << " + " << static_cast<int>(AUX_JOB_TIMEOUT) << ')');
return true;
}
if ((data_end - p) % DATA_ENTRY_SIZE) {
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " sent an invalid AUX_JOB_DONATION message (" << (data_end - p) << " is not a multiple of " << DATA_ENTRY_SIZE << ')');
return true;
}
hash digest;
sha256(buf, size, digest.h);
// Ignore repeated old messages
if (!server->m_auxJobMessages.emplace(*digest.u64(), data_timestamp).second) {
LOGWARN(5, "peer " << static_cast<char*>(m_addrString) << " sent an old AUX_JOB_DONATION message (" << (cur_time - data_timestamp) << " seconds old)");
return true;
}
#if defined(WITH_MERGE_MINING_DONATION) && defined(WITH_TLS) // Only work on verified jobs
const uint32_t N = static_cast<uint32_t>(data_end - p) / DATA_ENTRY_SIZE;
std::vector<IMergeMiningClient::ChainParameters> chain_params_vec(N);
for (uint32_t i = 0; i < N; ++i) {
IMergeMiningClient::ChainParameters& chain_params = chain_params_vec[i];
memcpy(chain_params.aux_id.h, p, HASH_SIZE);
p += HASH_SIZE;
memcpy(chain_params.aux_hash.h, p, HASH_SIZE);
p += HASH_SIZE;
chain_params.aux_diff.lo = read_unaligned(reinterpret_cast<const uint64_t*>(p));
p += sizeof(uint64_t);
chain_params.aux_diff.hi = read_unaligned(reinterpret_cast<const uint64_t*>(p));
p += sizeof(uint64_t);
}
server->m_pool->set_aux_job_donation(chain_params_vec);
#endif
server->broadcast_aux_job_donation(buf, size, data_timestamp, this, true);
return true;
}
bool P2PServer::P2PClient::handle_incoming_block_async(const PoolBlock* block, uint64_t max_time_delta)
{
P2PServer* server = static_cast<P2PServer*>(m_owner);
+41 -2
View File
@@ -34,12 +34,14 @@ static_assert((P2P_BUF_SIZE & (P2P_BUF_SIZE - 1)) == 0, "P2P_BUF_SIZE is not a p
static constexpr size_t PEER_LIST_RESPONSE_MAX_PEERS = 16;
static constexpr int DEFAULT_P2P_PORT = 37889;
static constexpr int DEFAULT_P2P_PORT_MINI = 37888;
static constexpr int DEFAULT_P2P_PORT_NANO = 37890;
static constexpr uint32_t PROTOCOL_VERSION_1_0 = 0x00010000UL;
static constexpr uint32_t PROTOCOL_VERSION_1_1 = 0x00010001UL;
static constexpr uint32_t PROTOCOL_VERSION_1_2 = 0x00010002UL;
static constexpr uint32_t PROTOCOL_VERSION_1_3 = 0x00010003UL;
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_2;
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_3;
class P2PServer : public TCPServer
{
@@ -55,7 +57,9 @@ public:
PEER_LIST_RESPONSE,
BLOCK_BROADCAST_COMPACT,
BLOCK_NOTIFY,
LAST = BLOCK_NOTIFY,
// Donation messages are signed by author's private keys to prevent their abuse/misuse.
AUX_JOB_DONATION,
LAST = AUX_JOB_DONATION,
};
explicit P2PServer(p2pool *pool);
@@ -113,6 +117,7 @@ public:
[[nodiscard]] bool on_peer_list_request(const uint8_t* buf);
void on_peer_list_response(const uint8_t* buf);
void on_block_notify(const uint8_t* buf);
[[nodiscard]] bool on_aux_job_donation(const uint8_t* buf, uint32_t size);
[[nodiscard]] bool handle_incoming_block_async(const PoolBlock* block, uint64_t max_time_delta = 0);
static void handle_incoming_block(p2pool* pool, PoolBlock& block, std::vector<hash>& missing_blocks, bool& result);
@@ -188,6 +193,12 @@ public:
bool disconnected() const { return m_seenGoodPeers && (m_numConnections == 0); };
#ifdef WITH_MERGE_MINING_DONATION
void broadcast_aux_job_donation_async(const uint8_t* data, uint32_t data_size, uint64_t timestamp);
#endif
void broadcast_aux_job_donation(const uint8_t* data, uint32_t data_size, uint64_t timestamp, const P2PClient* source, bool duplicate_check_done);
private:
[[nodiscard]] const char* get_log_category() const override;
@@ -291,6 +302,34 @@ private:
void on_shutdown() override;
void api_update_local_stats();
enum {
AUX_JOB_TIMEOUT = 3600,
};
unordered_set<std::pair<uint64_t, uint64_t>> m_auxJobMessages;
std::vector<uint8_t> m_auxJobLastMessage;
uint64_t m_auxJobLastMessageTimestamp;
void send_aux_job_donation(P2PServer::P2PClient* client, const uint8_t* data, uint32_t data_size);
void clean_aux_job_messages();
#ifdef WITH_MERGE_MINING_DONATION
struct AuxJobBroadcast
{
std::vector<uint8_t> job;
uint64_t timestamp = 0;
};
uv_mutex_t m_AuxJobBroadcastLock;
AuxJobBroadcast m_AuxJobBroadcast;
uv_async_t m_AuxJobBroadcastAsync;
static void on_aux_job_broadcast(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->broadcast_aux_job_donation_handler(); }
void broadcast_aux_job_donation_handler();
#endif
};
} // namespace p2pool
+296 -36
View File
@@ -38,14 +38,17 @@
#include "keccak.h"
#include "merkle.h"
#include "merge_mining_client.h"
#ifdef WITH_TLS
#include <openssl/curve25519.h>
#endif
#include <thread>
#include <fstream>
#include <numeric>
LOG_CATEGORY(P2Pool)
constexpr int BLOCK_HEADERS_REQUIRED = 720;
constexpr uint64_t SEEDHASH_EPOCH_BLOCKS = 2048;
constexpr uint64_t SEEDHASH_EPOCH_LAG = 64;
@@ -53,6 +56,8 @@ constexpr char FOUND_BLOCKS_FILE[] = "p2pool.blocks";
namespace p2pool {
static uint64_t BLOCK_HEADERS_REQUIRED = 720;
p2pool::p2pool(int argc, char* argv[])
: m_stopped(false)
, m_updateSeed(true)
@@ -73,6 +78,11 @@ p2pool::p2pool(int argc, char* argv[])
m_params = p;
// P2Pool-nano requires more Monero blocks for the initial sync
if (m_params->m_nano) {
BLOCK_HEADERS_REQUIRED = 1440;
}
bkg_jobs_tracker = new BackgroundJobTracker();
#ifdef WITH_UPNP
@@ -148,11 +158,18 @@ p2pool::p2pool(int argc, char* argv[])
uv_rwlock_init_checked(&m_minerDataLock);
uv_rwlock_init_checked(&m_ZMQReaderLock);
uv_rwlock_init_checked(&m_mergeMiningClientsLock);
#ifdef WITH_MERGE_MINING_DONATION
uv_rwlock_init_checked(&m_auxJobDonationLock);
#endif
uv_rwlock_init_checked(&m_auxIdLock);
uv_mutex_init_checked(&m_foundBlocksLock);
#ifdef WITH_RANDOMX
uv_mutex_init_checked(&m_minerLock);
#endif
uv_mutex_init_checked(&m_submitBlockDataLock);
uv_mutex_init_checked(&m_submitAuxBlockDataLock);
@@ -163,10 +180,10 @@ p2pool::p2pool(int argc, char* argv[])
throw std::exception();
}
m_sideChain = new SideChain(this, type, p->m_mini ? "mini" : nullptr);
m_sideChain = new SideChain(this, type, p->m_mini ? "mini" : (p->m_nano ? "nano" : nullptr));
if (p->m_p2pAddresses.empty()) {
const int p2p_port = m_sideChain->is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT;
const int p2p_port = m_sideChain->is_mini() ? DEFAULT_P2P_PORT_MINI : (m_sideChain->is_nano() ? DEFAULT_P2P_PORT_NANO : DEFAULT_P2P_PORT);
char buf[48] = {};
log::Stream s(buf);
@@ -222,11 +239,18 @@ p2pool::~p2pool()
uv_rwlock_destroy(&m_minerDataLock);
uv_rwlock_destroy(&m_ZMQReaderLock);
uv_rwlock_destroy(&m_mergeMiningClientsLock);
#ifdef WITH_MERGE_MINING_DONATION
uv_rwlock_destroy(&m_auxJobDonationLock);
#endif
uv_rwlock_destroy(&m_auxIdLock);
uv_mutex_destroy(&m_foundBlocksLock);
#ifdef WITH_RANDOMX
uv_mutex_destroy(&m_minerLock);
#endif
uv_mutex_destroy(&m_submitBlockDataLock);
uv_mutex_destroy(&m_submitAuxBlockDataLock);
@@ -565,6 +589,27 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
m_zmqLastActive = seconds_since_epoch();
}
#ifdef WITH_MERGE_MINING_DONATION
void p2pool::set_aux_job_donation(const std::vector<IMergeMiningClient::ChainParameters>& chain_params)
{
if (m_stopped) {
return;
}
const uint64_t t = seconds_since_epoch();
{
WriteLock lock(m_auxJobDonationLock);
m_auxJobDonation = chain_params;
m_auxJobDonationLastUpdated = t;
}
if (!chain_params.empty()) {
update_aux_data(chain_params.front().aux_id);
}
}
#endif
void p2pool::update_aux_data(const hash& chain_id)
{
if (m_stopped) {
@@ -574,6 +619,22 @@ void p2pool::update_aux_data(const hash& chain_id)
MinerData data;
std::vector<hash> aux_id;
#ifdef WITH_MERGE_MINING_DONATION
std::vector<IMergeMiningClient::ChainParameters> mm_donation_params;
uint64_t mm_donation_params_last_updated;
{
ReadLock lock(m_auxJobDonationLock);
mm_donation_params = m_auxJobDonation;
mm_donation_params_last_updated = m_auxJobDonationLastUpdated;
}
const uint64_t t = seconds_since_epoch();
if (!mm_donation_params.empty()) {
LOGINFO(5, "update_aux_data: there are " << mm_donation_params.size() << " aux chain datas for merge mining donation, last updated " << (t - mm_donation_params_last_updated) << " seconds ago");
}
#endif
{
ReadLock lock(m_mergeMiningClientsLock);
@@ -588,13 +649,33 @@ void p2pool::update_aux_data(const hash& chain_id)
if (c->get_params(chain_params)) {
data.aux_chains.emplace_back(chain_params.aux_id, chain_params.aux_hash, chain_params.aux_diff);
aux_id.emplace_back(chain_params.aux_id);
#ifdef WITH_MERGE_MINING_DONATION
// If the user is already merge mining this chain, don't use it for donation
mm_donation_params.erase(std::remove_if(mm_donation_params.begin(), mm_donation_params.end(), [&chain_params](const auto& t) { return t.aux_id == chain_params.aux_id; }), mm_donation_params.end());
#endif
}
}
aux_id.emplace_back(m_sideChain->consensus_hash());
}
}
if (!aux_id.empty()) {
#ifdef WITH_MERGE_MINING_DONATION
// Use the donation job for 30 minutes at most if it doesn't get updated anymore
if (t <= mm_donation_params_last_updated + 1800) {
LOGINFO(5, "update_aux_data: using " << mm_donation_params.size() << " aux chain datas for merge mining donation");
for (const IMergeMiningClient::ChainParameters& c : mm_donation_params) {
data.aux_chains.emplace_back(c.aux_id, c.aux_hash, c.aux_diff);
aux_id.emplace_back(c.aux_id);
}
}
else {
LOGINFO(5, "update_aux_data: merge mining donation data is stale, not using it");
}
#endif
aux_id.emplace_back(m_sideChain->consensus_hash());
{
WriteLock lock(m_auxIdLock);
if (aux_id == m_auxId) {
@@ -605,7 +686,7 @@ void p2pool::update_aux_data(const hash& chain_id)
m_auxNonce = data.aux_nonce;
}
else {
LOGERR(1, "Failed to find the aux nonce for merge mining. Merge mining will be off this round.");
LOGERR(1, "update_aux_data: failed to find the aux nonce for merge mining. Merge mining will be off this round.");
data.aux_chains.clear();
}
}
@@ -623,16 +704,111 @@ void p2pool::update_aux_data(const hash& chain_id)
}
if (!chain_id.empty()) {
LOGINFO(4, "New aux data from chain " << chain_id);
LOGINFO(4, "update_aux_data: new aux data from chain " << chain_id);
if (!is_main_thread()) {
update_block_template_async();
}
else {
update_block_template();
}
#if defined(WITH_MERGE_MINING_DONATION) && defined(WITH_TLS)
send_aux_job_donation();
#endif
}
}
#ifdef WITH_MERGE_MINING_DONATION
void p2pool::send_aux_job_donation()
{
#ifdef WITH_TLS
if (m_params->m_authorKeyFile.empty()) {
return;
}
std::ifstream f(m_params->m_authorKeyFile, std::ios::binary | std::ios::ate);
if (!f.good()) {
LOGERR(1, "send_aux_job_donation: failed to open " << m_params->m_authorKeyFile);
return;
}
Params::AuthorKey key;
if (f.tellg() != static_cast<std::streampos>(sizeof(key))) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << " has an invalid size");
return;
}
f.seekg(0);
f.read(reinterpret_cast<char*>(&key), sizeof(key));
if (!f.good()) {
LOGERR(1, "send_aux_job_donation: failed to read data from " << m_params->m_authorKeyFile);
return;
}
const uint64_t timestamp = time(nullptr);
if (timestamp >= read_unaligned(reinterpret_cast<uint64_t*>(key.expiration_time))) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << " is expired");
return;
}
const uint8_t* p = reinterpret_cast<uint8_t*>(&key);
if (!ED25519_verify(p, sizeof(key.pub_key) + sizeof(key.expiration_time), key.master_key_signature, ED25519_MASTER_PUBLIC_KEY)) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << ": signature verification failed");
return;
}
std::vector<uint8_t> job;
job.reserve(512);
constexpr uint32_t DATA_OFFSET = sizeof(key.pub_key) + sizeof(key.expiration_time) + sizeof(key.master_key_signature);
job.assign(p, p + DATA_OFFSET);
job.insert(job.end(), reinterpret_cast<const uint8_t*>(&timestamp), reinterpret_cast<const uint8_t*>(&timestamp) + sizeof(uint64_t));
{
ReadLock lock(m_minerDataLock);
if (m_minerData.aux_chains.empty()) {
LOGERR(1, "send_aux_job_donation: no merge mined chains found");
return;
}
for (const AuxChainData& c : m_minerData.aux_chains) {
job.insert(job.end(), c.unique_id.h, c.unique_id.h + HASH_SIZE);
job.insert(job.end(), c.data.h, c.data.h + HASH_SIZE);
job.insert(job.end(), reinterpret_cast<const uint8_t*>(&c.difficulty), reinterpret_cast<const uint8_t*>(&c.difficulty) + sizeof(difficulty_type));
}
}
uint8_t signature[64];
if (!ED25519_sign(signature, job.data() + DATA_OFFSET, job.size() - DATA_OFFSET, key.priv_key)) {
LOGERR(1, "send_aux_job_donation: failed to sign the donation job");
return;
}
if (!ED25519_verify(job.data() + DATA_OFFSET, job.size() - DATA_OFFSET, signature, key.pub_key)) {
LOGERR(1, "send_aux_job_donation: failed to verify the donation job's signature");
return;
}
OPENSSL_cleanse(&key, sizeof(key));
job.insert(job.end(), signature, signature + sizeof(signature));
m_p2pServer->broadcast_aux_job_donation_async(job.data(), static_cast<uint32_t>(job.size()), timestamp);
#else
LOGERR(1, "p2pool::send_aux_job_donation() must be built with TLS");
#endif
}
#endif
void p2pool::submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce)
{
{
@@ -769,7 +945,7 @@ void p2pool::submit_aux_block() const
}
}
c->submit_solution(block_tpl, hashing_blob, nonce_offset, seed_hash, blob, proof, path);
c->submit_solution(block_tpl->get_coinbase_merkle_proof(), hashing_blob, nonce_offset, seed_hash, blob, proof, path);
}
else {
LOGWARN(3, "submit_aux_block: failed to get merkle proof for chain_id " << chain_id);
@@ -977,7 +1153,7 @@ void p2pool::update_block_template()
#endif
}
void p2pool::download_block_headers(uint64_t current_height)
void p2pool::download_block_headers1(uint64_t current_height)
{
const uint64_t seed_height = get_seed_height(current_height);
const uint64_t prev_seed_height = (seed_height > SEEDHASH_EPOCH_BLOCKS) ? (seed_height - SEEDHASH_EPOCH_BLOCKS) : 0;
@@ -987,37 +1163,107 @@ void p2pool::download_block_headers(uint64_t current_height)
const Params::Host& host = current_host();
// First download 2 RandomX seeds
const uint64_t seed_heights[2] = { prev_seed_height, seed_height };
for (uint64_t height : seed_heights) {
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << prev_seed_height << "}}\0";
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, prev_seed_height, current_height](const char* data, size_t size, double) {
ChainMain block;
if (parse_block_header(data, size, block)) {
// Do it synchronously to make sure stratum and p2p don't start before it's finished
m_hasher->set_old_seed(block.id);
download_block_headers2(current_height);
}
else {
LOGERR(1, "fatal error: couldn't download block header for seed height " << prev_seed_height);
download_block_headers1(current_height);
}
},
[this, prev_seed_height, current_height](const char* data, size_t size, double) {
if (size > 0) {
LOGERR(1, "fatal error: couldn't download block header for seed height " << prev_seed_height << ", error " << log::const_buf(data, size));
download_block_headers1(current_height);
}
});
}
void p2pool::download_block_headers2(uint64_t current_height)
{
const uint64_t seed_height = get_seed_height(current_height);
char buf[log::Stream::BUF_SIZE + 1] = {};
log::Stream s(buf);
const Params::Host& host = current_host();
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << seed_height << "}}\0";
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, seed_height, current_height](const char* data, size_t size, double) {
ChainMain block;
if (parse_block_header(data, size, block)) {
const uint64_t start_height = (current_height > BLOCK_HEADERS_REQUIRED) ? (current_height - BLOCK_HEADERS_REQUIRED) : 0;
download_block_headers3(start_height, current_height);
}
else {
LOGERR(1, "fatal error: couldn't download block header for seed height " << seed_height);
download_block_headers2(current_height);
}
},
[this, seed_height, current_height](const char* data, size_t size, double) {
if (size > 0) {
LOGERR(1, "fatal error: couldn't download block header for seed height " << seed_height << ", error " << log::const_buf(data, size));
download_block_headers2(current_height);
}
});
}
void p2pool::download_block_headers3(uint64_t start_height, uint64_t current_height)
{
// Workaround the restricted RPC limit
constexpr uint64_t RESTRICTED_BLOCK_HEADER_RANGE = 1000;
if (current_height - start_height > RESTRICTED_BLOCK_HEADER_RANGE + 1) {
char buf[log::Stream::BUF_SIZE + 1] = {};
log::Stream s(buf);
const Params::Host& host = current_host();
const uint64_t next_height = start_height + RESTRICTED_BLOCK_HEADER_RANGE;
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << height << "}}\0";
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << next_height << "}}\0";
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, prev_seed_height, height](const char* data, size_t size, double)
{
ChainMain block;
if (parse_block_header(data, size, block)) {
if (height == prev_seed_height) {
// Do it synchronously to make sure stratum and p2p don't start before it's finished
m_hasher->set_old_seed(block.id);
}
[this, start_height, next_height, host, current_height](const char* data, size_t size, double) {
if (parse_block_headers_range(data, size) == next_height - start_height + 1) {
download_block_headers3(next_height + 1, current_height);
}
else {
LOGERR(1, "fatal error: couldn't download block header for seed height " << height);
PANIC_STOP();
LOGERR(1, "Couldn't download block headers for heights " << start_height << " - " << next_height);
download_block_headers3(start_height, current_height);
}
},
[height](const char* data, size_t size, double)
{
[this, start_height, next_height, current_height](const char* data, size_t size, double) {
if (size > 0) {
LOGERR(1, "fatal error: couldn't download block header for seed height " << height << ", error " << log::const_buf(data, size));
PANIC_STOP();
LOGERR(1, "Couldn't download block headers for heights " << start_height << " - " << next_height << ", error " << log::const_buf(data, size));
download_block_headers3(start_height, current_height);
}
});
}
);
}
else {
download_block_headers4(start_height, current_height);
}
}
const uint64_t start_height = (current_height > BLOCK_HEADERS_REQUIRED) ? (current_height - BLOCK_HEADERS_REQUIRED) : 0;
void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_height)
{
char buf[log::Stream::BUF_SIZE + 1] = {};
log::Stream s(buf);
const Params::Host& host = current_host();
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << current_height - 1 << "}}\0";
@@ -1080,14 +1326,14 @@ void p2pool::download_block_headers(uint64_t current_height)
}
else {
LOGERR(1, "Couldn't download block headers for heights " << start_height << " - " << current_height - 1);
download_block_headers(current_height);
download_block_headers4(start_height, current_height);
}
},
[this, start_height, current_height](const char* data, size_t size, double)
{
if (size > 0) {
LOGERR(1, "Couldn't download block headers for heights " << start_height << " - " << current_height - 1 << ", error " << log::const_buf(data, size));
download_block_headers(current_height);
download_block_headers4(start_height, current_height);
}
});
}
@@ -1439,7 +1685,7 @@ void p2pool::parse_get_miner_data_rpc(const char* data, size_t size)
handle_miner_data(minerData);
if (m_serversStarted.load() == 0) {
download_block_headers(minerData.height);
download_block_headers1(minerData.height);
}
}
@@ -1693,7 +1939,7 @@ void p2pool::cleanup_mainchain_data(uint64_t height)
// Expects m_mainchainLock to be already locked here
// Deletes everything older than 720 blocks, except for the 3 latest RandomX seed heights
constexpr uint64_t PRUNE_DISTANCE = BLOCK_HEADERS_REQUIRED;
const uint64_t PRUNE_DISTANCE = BLOCK_HEADERS_REQUIRED;
const uint64_t seed_height = get_seed_height(height);
const std::array<uint64_t, 3> seed_heights{ seed_height, seed_height - SEEDHASH_EPOCH_BLOCKS, seed_height - SEEDHASH_EPOCH_BLOCKS * 2 };
@@ -1769,6 +2015,15 @@ void p2pool::api_update_block_found(const ChainMain* data, const PoolBlock* bloc
}
}
void p2pool::on_external_block(const PoolBlock& block)
{
ReadLock lock(m_mergeMiningClientsLock);
for (IMergeMiningClient* c : m_mergeMiningClients) {
c->on_external_block(block);
}
}
bool p2pool::get_difficulty_at_height(uint64_t height, difficulty_type& diff)
{
ReadLock lock(m_mainchainLock);
@@ -1956,7 +2211,7 @@ int p2pool::run()
loop->data = nullptr;
GetLoopUserData(loop);
set_thread_name("Main");
set_thread_name("p2pool");
try {
get_info();
@@ -1979,7 +2234,12 @@ int p2pool::run()
bkg_jobs_tracker->wait();
#ifdef WITH_RANDOMX
delete m_miner;
{
MutexLock lock(m_minerLock);
delete m_miner;
m_miner = nullptr;
}
#endif
delete m_stratumServer;
delete m_p2pServer;
+18 -1
View File
@@ -19,6 +19,7 @@
#include "uv_util.h"
#include "params.h"
#include "merge_mining_client.h"
#include <map>
namespace p2pool {
@@ -86,6 +87,11 @@ public:
virtual void handle_miner_data(MinerData& data) override;
virtual void handle_chain_main(ChainMain& data, const char* extra) override;
#ifdef WITH_MERGE_MINING_DONATION
void set_aux_job_donation(const std::vector<IMergeMiningClient::ChainParameters>& chain_params);
void send_aux_job_donation();
#endif
void update_aux_data(const hash& chain_id);
void submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce);
@@ -106,11 +112,16 @@ public:
void update_block_template_async(bool is_alternative_block = false);
void update_block_template();
void download_block_headers(uint64_t current_height);
// TODO refactor this bullshit later
void download_block_headers1(uint64_t current_height);
void download_block_headers2(uint64_t current_height);
void download_block_headers3(uint64_t start_height, uint64_t current_height);
void download_block_headers4(uint64_t start_height, uint64_t current_height);
bool chainmain_get_by_hash(const hash& id, ChainMain& data) const;
void api_update_block_found(const ChainMain* data, const PoolBlock* block, bool update_stats_mod = true);
void on_external_block(const PoolBlock& block);
bool get_difficulty_at_height(uint64_t height, difficulty_type& diff);
@@ -251,6 +262,12 @@ private:
mutable uv_rwlock_t m_mergeMiningClientsLock;
std::vector<IMergeMiningClient*> m_mergeMiningClients;
#ifdef WITH_MERGE_MINING_DONATION
mutable uv_rwlock_t m_auxJobDonationLock;
std::vector<IMergeMiningClient::ChainParameters> m_auxJobDonation;
uint64_t m_auxJobDonationLastUpdated = 0;
#endif
mutable uv_rwlock_t m_auxIdLock;
std::vector<hash> m_auxId;
uint32_t m_auxNonce = 0;
+17
View File
@@ -153,6 +153,11 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if (strcmp(argv[i], "--nano") == 0) {
m_nano = true;
ok = true;
}
if (strcmp(argv[i], "--no-autodiff") == 0) {
m_autoDiff = false;
ok = true;
@@ -238,6 +243,13 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
#ifdef WITH_MERGE_MINING_DONATION
if ((strcmp(argv[i], "--adkf") == 0) && (i + 1 < argc)) {
m_authorKeyFile = argv[++i];
ok = true;
}
#endif
if (!ok) {
// Wait to avoid log messages overlapping with printf() calls and making a mess on screen
std::this_thread::sleep_for(std::chrono::milliseconds(10));
@@ -293,6 +305,11 @@ bool Params::valid() const
}
#endif
if (m_mini && m_nano) {
LOGERR(1, "You can't have both --mini and --nano in the command line");
return false;
}
return true;
}
+12
View File
@@ -85,6 +85,7 @@ struct Params
uint32_t m_maxIncomingPeers = 450;
uint32_t m_minerThreads = 0;
bool m_mini = false;
bool m_nano = false;
bool m_autoDiff = true;
std::string m_socks5Proxy;
bool m_dns = true;
@@ -101,6 +102,17 @@ struct Params
std::string m_tlsCertKey;
#endif
bool m_enableStratumHTTP = true;
#ifdef WITH_MERGE_MINING_DONATION
std::string m_authorKeyFile;
struct AuthorKey {
uint8_t pub_key[32];
uint8_t expiration_time[8];
uint8_t master_key_signature[64];
uint8_t priv_key[64];
};
#endif
};
} // namespace p2pool
+26
View File
@@ -128,6 +128,11 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b)
m_auxChains = b.m_auxChains;
m_auxNonce = b.m_auxNonce;
m_hashingBlob = b.m_hashingBlob;
m_powHash = b.m_powHash;
m_seed = b.m_seed;
return *this;
}
@@ -321,18 +326,32 @@ void PoolBlock::reset_offchain_data()
m_auxChains.shrink_to_fit();
m_auxNonce = 0;
m_hashingBlob.clear();
m_hashingBlob.shrink_to_fit();
m_powHash = {};
m_seed = {};
}
bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash, bool force_light_mode)
{
// Calculate the coinbase tx hash, then the merkle root of all transactions in the block - this merkle root is what goes into the hashing blob
// Monero transactions are hashed in 3 separate parts, the resulting 3 hashes are then hashed together to get the final result
// For the reference, see "calculate_transaction_hash" in Monero's src/cryptonote_basic/cryptonote_format_utils.cpp
alignas(8) uint8_t hashes[HASH_SIZE * 3];
uint64_t* second_hash = reinterpret_cast<uint64_t*>(hashes + HASH_SIZE);
// Second hash is keccak of base rct data (it doesn't exist for the coinbase transaction, so it's a hash of a single 0x00 byte)
second_hash[0] = 0x14281e7a9e7836bcull;
second_hash[1] = 0x7d818f8229424636ull;
second_hash[2] = 0x9165d677b4f71266ull;
second_hash[3] = 0x8ac9bc64e0a996ffull;
// Third hash is null because there is no rct data in the coinbase transaction
memset(hashes + HASH_SIZE * 2, 0, HASH_SIZE);
uint64_t count;
@@ -354,6 +373,8 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
const uint8_t* miner_tx = mainchain_data.data() + header_size;
hash tmp;
// "miner_tx_size - 1" because the last byte is 0x00 (base rct data), it goes into the second hash
keccak(miner_tx, static_cast<int>(miner_tx_size) - 1, tmp.h);
memcpy(hashes, tmp.h, HASH_SIZE);
@@ -361,6 +382,8 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
uint8_t* h = reinterpret_cast<uint8_t*>(m_transactions.data());
keccak(reinterpret_cast<uint8_t*>(hashes), HASH_SIZE * 3, tmp.h);
// Save the coinbase tx hash into the first element of m_transactions
memcpy(h, tmp.h, HASH_SIZE);
root_hash tmp_root;
@@ -371,6 +394,9 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
writeVarint(count, [&blob, &blob_size](uint8_t b) { blob[blob_size++] = b; });
// cppcheck-suppress danglingLifetime
m_hashingBlob.assign(blob, blob + blob_size);
return hasher->calculate(blob, blob_size, height, seed_hash, pow_hash, force_light_mode);
}
+5 -1
View File
@@ -144,7 +144,7 @@ struct PoolBlock
// Merge mining extra data
// Format: vector of (chain ID, chain data) pairs
// Chain data format is arbitrary and depends on the merge mined chain's requirements
// Chain data always has merge mining hash and difficulty in the beginning, the rest is arbitrary and depends on the merge mined chain's requirements
std::map<hash, std::vector<uint8_t>> m_mergeMiningExtra;
// Arbitrary extra data
@@ -173,6 +173,10 @@ struct PoolBlock
std::vector<AuxChainData> m_auxChains;
uint32_t m_auxNonce;
std::vector<uint8_t> m_hashingBlob;
hash m_powHash;
hash m_seed;
std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr, const uint32_t* nonce = nullptr, const uint32_t* extra_nonce = nullptr) const;
std::vector<uint8_t> serialize_sidechain_data() const;
+26 -10
View File
@@ -57,6 +57,7 @@ namespace p2pool {
static constexpr uint8_t default_consensus_id[HASH_SIZE] = { 34,175,126,231,181,11,104,146,227,153,218,107,44,108,68,39,178,81,4,212,169,4,142,0,177,110,157,240,68,7,249,24 };
static constexpr uint8_t mini_consensus_id[HASH_SIZE] = { 57,130,201,26,149,174,199,250,66,80,189,18,108,216,194,220,136,23,63,24,64,113,221,44,219,86,39,163,53,24,126,196 };
static constexpr uint8_t nano_consensus_id[HASH_SIZE] = { 171,248,206,148,210,226,114,99,250,145,221,96,13,216,23,63,104,53,129,168,244,80,141,138,157,250,50,54,37,189,5,89 };
NetworkType SideChain::s_networkType = NetworkType::Invalid;
@@ -84,6 +85,11 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
LOGINFO(1, log::LightCyan() << "network type = " << type);
if (m_poolName == "nano") {
m_targetBlockTime = 30;
m_unclePenalty = 10;
}
if (m_pool && !load_config(m_pool->params().m_sidechainConfig)) {
PANIC_STOP();
}
@@ -118,6 +124,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
constexpr char default_config[] = "mainnet\0" "default\0" "\0" "10\0" "100000\0" "2160\0" "20\0";
constexpr char mini_config[] = "mainnet\0" "mini\0" "\0" "10\0" "100000\0" "2160\0" "20\0";
constexpr char nano_config[] = "mainnet\0" "nano\0" "\0" "30\0" "100000\0" "2160\0" "10\0";
// Hardcoded default consensus ID
if ((s.m_pos == sizeof(default_config) - 1) && (memcmp(buf, default_config, sizeof(default_config) - 1) == 0)) {
@@ -127,6 +134,10 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
else if ((s.m_pos == sizeof(mini_config) - 1) && (memcmp(buf, mini_config, sizeof(mini_config) - 1) == 0)) {
m_consensusId.assign(mini_consensus_id, mini_consensus_id + HASH_SIZE);
}
// Hardcoded nano consensus ID
else if ((s.m_pos == sizeof(nano_config) - 1) && (memcmp(buf, nano_config, sizeof(nano_config) - 1) == 0)) {
m_consensusId.assign(nano_consensus_id, nano_consensus_id + HASH_SIZE);
}
else {
#ifdef WITH_RANDOMX
const randomx_flags flags = randomx_get_flags();
@@ -573,15 +584,13 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
LOGWARN(3, "add_external_block: block is built on top of an unknown mainchain block " << block.m_prevId << ", mainchain reorg might've happened");
}
hash seed;
if (!m_pool->get_seed(block.m_txinGenHeight, seed)) {
if (!m_pool->get_seed(block.m_txinGenHeight, block.m_seed)) {
LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": couldn't get seed hash for mainchain height " << block.m_txinGenHeight);
forget_incoming_block(block);
return false;
}
hash pow_hash;
if (!block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash)) {
if (!block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, block.m_seed, block.m_powHash)) {
LOGWARN(3, "add_external_block: couldn't get PoW hash for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight << ". Ignoring it.");
forget_incoming_block(block);
return true;
@@ -589,7 +598,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
// Check if it has the correct parent and difficulty to go right to monerod for checking
MinerData miner_data = m_pool->miner_data();
if ((block.m_prevId == miner_data.prev_id) && miner_data.difficulty.check_pow(pow_hash)) {
if ((block.m_prevId == miner_data.prev_id) && miner_data.difficulty.check_pow(block.m_powHash)) {
LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero network, submitting it");
m_pool->submit_block_async(block.serialize_mainchain_data());
}
@@ -598,13 +607,13 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
if (!m_pool->get_difficulty_at_height(block.m_txinGenHeight, diff)) {
LOGWARN(3, "add_external_block: couldn't get mainchain difficulty for height = " << block.m_txinGenHeight);
}
else if (diff.check_pow(pow_hash)) {
else if (diff.check_pow(block.m_powHash)) {
LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero height " << block.m_txinGenHeight << ", submitting it");
m_pool->submit_block_async(block.serialize_mainchain_data());
}
}
if (!block.m_difficulty.check_pow(pow_hash)) {
if (!block.m_difficulty.check_pow(block.m_powHash)) {
LOGWARN(3,
"add_external_block mined by " << block.m_minerWallet <<
": not enough PoW for height = " << block.m_sidechainHeight <<
@@ -617,8 +626,8 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
// Calculate the same hash second time to check if it's an unstable hardware that caused this
hash pow_hash2;
if (block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash2, true) && (pow_hash2 != pow_hash)) {
LOGERR(0, "UNSTABLE HARDWARE DETECTED: Calculated the same hash twice, got different results: " << pow_hash << " != " << pow_hash2 << " (sidechain id = " << block.m_sidechainId << ')');
if (block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, block.m_seed, pow_hash2, true) && (pow_hash2 != block.m_powHash)) {
LOGERR(0, "UNSTABLE HARDWARE DETECTED: Calculated the same hash twice, got different results: " << block.m_powHash << " != " << pow_hash2 << " (sidechain id = " << block.m_sidechainId << ')');
if (block.m_difficulty.check_pow(pow_hash2)) {
LOGINFO(3, "add_external_block second result has enough PoW for height = " << block.m_sidechainHeight << ", id = " << block.m_sidechainId);
not_enough_pow = false;
@@ -630,6 +639,8 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
}
}
m_pool->on_external_block(block);
bool block_found = false;
missing_blocks.clear();
@@ -1062,7 +1073,7 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
"\nMonero node = " << m_pool->current_host().m_displayName <<
"\nMain chain height = " << m_pool->block_template().height() <<
"\nMain chain hashrate = " << log::Hashrate(network_hashrate) <<
"\nSide chain ID = " << (is_default() ? "default" : (is_mini() ? "mini" : m_consensusIdDisplayStr.c_str())) <<
"\nSide chain ID = " << (is_default() ? "default" : (is_mini() ? "mini" : (is_nano() ? "nano" : m_consensusIdDisplayStr.c_str()))) <<
"\nSide chain height = " << tip_height + 1 <<
"\nSide chain hashrate = " << log::Hashrate(pool_hashrate) <<
(hashrate_est ? "\nYour hashrate (pool-side) = " : "") << (hashrate_est ? log::Hashrate(hashrate_est) : log::Hashrate()) <<
@@ -1185,6 +1196,11 @@ bool SideChain::is_mini() const
return (memcmp(m_consensusId.data(), mini_consensus_id, HASH_SIZE) == 0);
}
bool SideChain::is_nano() const
{
return (memcmp(m_consensusId.data(), nano_consensus_id, HASH_SIZE) == 0);
}
uint64_t SideChain::bottom_height(const PoolBlock* tip) const
{
if (!tip) {
+1
View File
@@ -79,6 +79,7 @@ public:
[[nodiscard]] uint64_t last_updated() const;
[[nodiscard]] bool is_default() const;
[[nodiscard]] bool is_mini() const;
[[nodiscard]] bool is_nano() const;
[[nodiscard]] uint64_t bottom_height(const PoolBlock* tip) const;
[[nodiscard]] const PoolBlock* chainTip() const { return m_chainTip; }
+21
View File
@@ -891,6 +891,26 @@ void StratumServer::update_hashrate_data(uint64_t hashes, uint64_t timestamp)
if (hashes) {
m_cumulativeHashes += hashes;
++m_totalStratumShares;
// P2Pool-nano warning
#ifndef P2POOL_LOG_DISABLE
// Check the hashrate when enough shares is found
if (((m_totalStratumShares & 63) == 0) && m_pool->side_chain().is_nano()) {
const HashrateData& head = m_hashrateData[m_hashrateDataHead];
const HashrateData& tail = m_hashrateData[m_hashrateDataTail_24h];
const int64_t dt = static_cast<int64_t>(head.m_timestamp - tail.m_timestamp);
if (dt > 0) {
const uint64_t total_hashes = head.m_cumulativeHashes - tail.m_cumulativeHashes;
const uint64_t hashrate = total_hashes / dt;
if (hashrate > 30000) {
LOGINFO(0, log::LightRed() << "Your hashrate is " << log::Hashrate(hashrate) << ". Please switch from P2Pool-nano to P2Pool-mini or P2Pool-main. P2Pool-nano is recommended only for small-scale miners.");
}
}
}
#endif // P2POOL_LOG_DISABLE
}
HashrateData* data = m_hashrateData;
@@ -1533,6 +1553,7 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
<< ",\"connections\":" << connections
<< ",\"incoming_connections\":" << incoming_connections
<< ",\"block_reward_share_percent\":" << block_reward_share_percent
<< ",\"wallet\":\"" << m_pool->params().m_wallet << '"'
<< ",\"workers\":[";
const difficulty_type pool_diff = m_pool->side_chain().difficulty();
+2
View File
@@ -60,6 +60,8 @@ const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MIN
#endif
" on " __DATE__ ")";
const uint8_t ED25519_MASTER_PUBLIC_KEY[32] = {51,175,37,73,203,241,188,115,195,255,123,53,218,120,90,74,186,240,82,178,67,139,124,91,180,106,188,181,187,51,236,10};
std::string DATA_DIR;
SoftwareID get_software_id(uint32_t value)
+13 -2
View File
@@ -35,13 +35,15 @@
namespace p2pool {
#define P2POOL_VERSION_MAJOR 4
#define P2POOL_VERSION_MINOR 5
#define P2POOL_VERSION_MINOR 7
#define P2POOL_VERSION_PATCH 0
constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;
extern const char* VERSION;
extern const uint8_t ED25519_MASTER_PUBLIC_KEY[32];
extern std::string DATA_DIR;
enum class SoftwareID : uint32_t {
@@ -67,7 +69,16 @@ template<typename T>
struct ScopeGuard : public nocopy_nomove
{
explicit FORCEINLINE ScopeGuard(T&& handler) : m_handler(std::move(handler)) {}
FORCEINLINE ~ScopeGuard() { m_handler(); }
FORCEINLINE ~ScopeGuard()
{
// Because the handler can throw an exception, and we don't want exceptions in a destructor
try {
m_handler();
}
catch(...) {
}
}
T m_handler;
};
+9 -2
View File
@@ -22,14 +22,21 @@ if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
include(cmake/msvc_libs.cmake)
endif()
add_subdirectory(../external/src/RandomX RandomX)
set(LIBS ${LIBS} randomx)
if (STATIC_LIBS AND WIN32 AND (CMAKE_CXX_COMPILER_ID MATCHES Clang))
set(LIBS ${LIBS} "${CMAKE_SOURCE_DIR}/../build/external/src/RandomX/librandomx.a")
else()
add_subdirectory(../external/src/RandomX RandomX)
set(LIBS ${LIBS} randomx)
endif()
add_definitions(-DWITH_RANDOMX)
add_subdirectory(cmake/ssl)
include_directories(../external/src/grpc/third_party/boringssl-with-bazel/src/include)
add_definitions(-DWITH_TLS)
add_definitions(-DWITH_MERGE_MINING_DONATION)
add_definitions(-DP2POOL_UNIT_TESTS)
add_definitions(-DP2POOL_SIDECHAIN_EXTRA_1=1)