Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20c3973504 | |||
| 16b74edc51 | |||
| d611056b1c | |||
| ecc33cfebb | |||
| 0ae2af0bb8 | |||
| bdd34c5f56 | |||
| bbee372a01 | |||
| 5c907d39aa | |||
| 6d3fbc5467 | |||
| 068b286a88 | |||
| b7c4613d40 | |||
| 971f804a6e | |||
| 830c78a032 | |||
| 50634e5e79 | |||
| c5fba9992e | |||
| 29df28d3c8 | |||
| 4a2b75c7fb | |||
| 2a9cf67c3a | |||
| 3bcde151ee | |||
| b22088f330 | |||
| bfb0b5383a | |||
| 560f62a427 | |||
| 271a30998f |
@@ -19,9 +19,9 @@ jobs:
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20
|
||||
sudo apt-get install -y clang-tidy-20
|
||||
clang-tidy-20 --verify-config
|
||||
sudo ./llvm.sh 21
|
||||
sudo apt-get install -y clang-tidy-21
|
||||
clang-tidy-21 --verify-config
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -32,9 +32,9 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DDEV_CLANG_TIDY=ON -DSTATIC_LIBS=ON -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
|
||||
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DDEV_CLANG_TIDY=ON -DSTATIC_LIBS=ON -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
|
||||
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
cd src
|
||||
clang-tidy-20 *.cpp -p ../build -checks=-clang-diagnostic-undefined-internal,-clang-analyzer-optin.performance.Padding,-clang-diagnostic-nan-infinity-disabled -warnings-as-errors=* -header-filter=^[^\.]
|
||||
clang-tidy-21 *.cpp -p ../build -checks=-clang-diagnostic-undefined-internal,-clang-analyzer-optin.performance.Padding,-clang-diagnostic-nan-infinity-disabled -warnings-as-errors=* -header-filter=^[^\.]
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 20 all
|
||||
sudo ./llvm.sh 21 all
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DDEV_DEBUG=ON -DWITH_COVERAGE=ON -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DDEV_DEBUG=ON -DWITH_COVERAGE=ON -DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
|
||||
make -j$(nproc) p2pool_tests
|
||||
|
||||
- name: Run tests
|
||||
@@ -50,12 +50,12 @@ jobs:
|
||||
- name: Merge profile data
|
||||
run: |
|
||||
cd tests/build
|
||||
llvm-profdata-20 merge -sparse ./p2pool_tests.profraw -o ./p2pool_tests.profdata
|
||||
llvm-profdata-21 merge -sparse ./p2pool_tests.profraw -o ./p2pool_tests.profdata
|
||||
|
||||
- name: Export profile data
|
||||
run: |
|
||||
cd tests/build
|
||||
llvm-cov-20 export ./p2pool_tests -format=lcov -instr-profile=./p2pool_tests.profdata > coverage.info
|
||||
llvm-cov-21 export ./p2pool_tests -format=lcov -instr-profile=./p2pool_tests.profdata > coverage.info
|
||||
|
||||
- name: Run genhtml
|
||||
run: |
|
||||
|
||||
@@ -154,7 +154,7 @@ sudo sysctl vm.nr_hugepages=3072
|
||||
4. Check that ports 18080 (Monero p2p port) and 37889/37888 (P2Pool/P2Pool mini p2p port) are open in your local firewall to ensure better connectivity.
|
||||
5. Start `monerod` with the following command/options:
|
||||
```
|
||||
./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist
|
||||
```
|
||||
**Note:**
|
||||
The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
@@ -163,7 +163,7 @@ The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
|
||||
`--add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
|
||||
`--disable-dns-checkpoints` is needed to avoid periodical lags when DNS is updated (it's not needed when mining)
|
||||
`--enforce-dns-checkpointing` is needed to combat the selfish mining attempts by malicious actors
|
||||
|
||||
`--enable-dns-blocklist` is needed to ban known bad nodes
|
||||
|
||||
@@ -222,7 +222,7 @@ nocreate
|
||||
|
||||
8. Start `monerod` with the following command/options:
|
||||
```
|
||||
.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist
|
||||
```
|
||||
**Note:**
|
||||
The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
@@ -231,7 +231,7 @@ The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
|
||||
`--add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
|
||||
`--disable-dns-checkpoints` is needed to avoid periodical lags when DNS is updated (it's not needed when mining)
|
||||
`--enforce-dns-checkpointing` is needed to combat the selfish mining attempts by malicious actors
|
||||
|
||||
`--enable-dns-blocklist` is needed to ban known bad nodes
|
||||
|
||||
@@ -253,7 +253,7 @@ The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
13. *(Optional but highly recommended)* You can create a Quickstart by creating a batch (.bat) file with the following contents and placing it in your P2Pool directory along with `xmrig.exe`.
|
||||
```
|
||||
@ECHO OFF
|
||||
start cmd /k %~dp0\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
start cmd /k %~dp0\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist
|
||||
ECHO Wait until the Monero daemon shows fully synced before continuing. This can take some time. Type 'status' in other window to check progress.
|
||||
PAUSE
|
||||
start cmd /k %~dp0\p2pool.exe --wallet YOUR_WALLET_ADDRESS --mini
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
../external/src/cryptonote/
|
||||
../external/src/libuv/
|
||||
../external/src/cppzmq/
|
||||
../external/src/libzmq/
|
||||
../external/src/libzmq/include/
|
||||
../external/src/miniupnp/miniupnpc/include/
|
||||
../external/src/randomx/src/
|
||||
../external/src/rapidjson/include/
|
||||
|
||||
+1
-1
@@ -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 -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
|
||||
"..\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 -DZMQ_VERSION=40306 -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
|
||||
|
||||
@@ -611,7 +611,7 @@ class MoneroConfigForm(ConfigFormBase):
|
||||
self.sync_pruned_blocks = self.add(
|
||||
npyscreen.Checkbox,
|
||||
name="Sync Pruned Blocks",
|
||||
value=False,
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"limit_data_rates": false,
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"sync_pruned_blocks": true,
|
||||
"fast_sync": true,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
|
||||
@@ -118,7 +118,7 @@ services:
|
||||
restart: unless-stopped
|
||||
command: >-
|
||||
--zmq-pub tcp://0.0.0.0:18083
|
||||
--disable-dns-checkpoints
|
||||
--enforce-dns-checkpointing
|
||||
--enable-dns-blocklist
|
||||
--out-peers 16
|
||||
--in-peers 32
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"limit_data_rates": false,
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"sync_pruned_blocks": true,
|
||||
"fast_sync": true,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
|
||||
@@ -94,7 +94,7 @@ services:
|
||||
restart: unless-stopped
|
||||
command: >-
|
||||
--zmq-pub tcp://0.0.0.0:18083
|
||||
--disable-dns-checkpoints
|
||||
--enforce-dns-checkpointing
|
||||
--enable-dns-blocklist
|
||||
--out-peers 16
|
||||
--in-peers 32
|
||||
@@ -111,6 +111,8 @@ services:
|
||||
|
||||
--prune-blockchain
|
||||
|
||||
--sync-pruned-blocks
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
FROM ubuntu:22.04 as builder
|
||||
ARG MONERO_GIT_TAG="latest"
|
||||
|
||||
RUN set -e && \
|
||||
apt-get update -q -y --no-install-recommends && \
|
||||
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
|
||||
RUN apt-get update -q -y --no-install-recommends && \
|
||||
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
|
||||
autoconf \
|
||||
automake \
|
||||
autotools-dev \
|
||||
bsdmainutils \
|
||||
@@ -15,32 +17,47 @@ RUN set -e && \
|
||||
ccache \
|
||||
cmake \
|
||||
curl \
|
||||
doxygen \
|
||||
git \
|
||||
libtool \
|
||||
graphviz \
|
||||
libtool libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev \
|
||||
qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev \
|
||||
libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev \
|
||||
pkg-config \
|
||||
python3 \
|
||||
gperf
|
||||
|
||||
|
||||
WORKDIR /src
|
||||
RUN git clone --recursive https://github.com/monero-project/monero && \
|
||||
|
||||
RUN git clone --recursive --branch release-v0.18 https://github.com/monero-project/monero && \
|
||||
cd monero && \
|
||||
if [ "x$MONERO_GIT_TAG" = "xlatest" ]; then MONERO_GIT_TAG=$(git describe --tags $(git rev-list --tags --max-count=1)); fi && \
|
||||
git checkout $MONERO_GIT_TAG && \
|
||||
git submodule sync && git submodule update --init --force --recursive && \
|
||||
make -j$(nproc) depends target=$(contrib/depends/config.guess)
|
||||
curl -L -O https://p2pool.io/checkpoints/checkpoints.dat && \
|
||||
curl -L -O https://p2pool.io/checkpoints/checkpoints.patch && \
|
||||
git apply checkpoints.patch && \
|
||||
cp -f checkpoints.dat src/blocks && \
|
||||
make -j$(nproc)
|
||||
|
||||
# ---
|
||||
|
||||
# runtime stage
|
||||
FROM ubuntu:22.04
|
||||
|
||||
COPY --from=0 /src/monero/build/*/release/bin /usr/local/bin/
|
||||
COPY --from=0 /src/monero/build/Linux/*/release/bin /usr/local/bin/
|
||||
|
||||
RUN set -e && \
|
||||
apt-get update -q -y --no-install-recommends && \
|
||||
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
|
||||
|
||||
RUN apt-get update -q -y --no-install-recommends && \
|
||||
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
netcat \
|
||||
libboost-chrono-dev libboost-filesystem-dev libboost-program-options-dev libboost-regex-dev libboost-thread-dev \
|
||||
libzmq5 \
|
||||
libreadline8 \
|
||||
libhidapi-libusb0 \
|
||||
libunbound8 \
|
||||
&& \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt
|
||||
|
||||
@@ -27,8 +27,9 @@ COPY --from=0 /usr/src/xmrig/build/xmrig /
|
||||
RUN set -e && \
|
||||
apt-get update -q -y --no-install-recommends && \
|
||||
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
|
||||
libssl1.1 \
|
||||
libcrypto++6 \
|
||||
libuv1 \
|
||||
libssl3 \
|
||||
libcrypto++8 \
|
||||
libhwloc15 \
|
||||
&& \
|
||||
apt-get clean
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
--rpc-ssl Enable SSL on RPC connections to the Monero node
|
||||
--rpc-ssl-fingerprint base64-encoded fingerprint of the Monero node's certificate (optional, use it for certificate pinning)
|
||||
--no-stratum-http Disable HTTP on Stratum ports
|
||||
--full-validation Enables full share validation / increases CPU usage
|
||||
```
|
||||
|
||||
### Example command line
|
||||
@@ -116,3 +117,11 @@ openssl x509 -in rpc_ssl.crt -pubkey -noout -inform pem | openssl pkey -pubin -o
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
|
||||
### Full validation
|
||||
|
||||
`--full-validation` is a boolean flag and will set the value to true; by default it is false to reduce CPU usage
|
||||
|
||||
Enable this if untrusted sources can submit shares to your p2pool server and you want to verify the validity of the shares PoW. Increases CPU usage.
|
||||
This option is for shared mining services, and not neccessary in local setups.
|
||||
@@ -248,7 +248,7 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<ul>
|
||||
<li>Download the latest Monero <a href="https://www.getmonero.org/downloads/" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>18080</span> (Monero p2p port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 8 --in-peers 16</span> instead.
|
||||
<li>Wait until it's fully synchronized. If you didn't run Monero node before, it can take up to several days to synchronize (5-6 hours on a modern PC with fast SSD and fast Internet connection). You can add <span>--prune-blockchain</span> argument to the command line to run a pruned node (3-4 times less disk usage)
|
||||
</ul></details>
|
||||
@@ -304,7 +304,7 @@ P2Pool is a decentralized community, there is no dedicated support. You can reac
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get an error "monerod RPC ... is incompatible, update to RPC >= v3.8"</span>
|
||||
<ul><li>Use monerod v0.18.0.0 or newer</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get warnings "peer ... is ahead on mainchain (height ..., your height ...). Is your monerod stuck or lagging?"</span>
|
||||
<ul><li>Make sure you add these arguments to monerod command line: <span style="color:#808080;">--zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist</span></ul><br>
|
||||
<ul><li>Make sure you add these arguments to monerod command line: <span style="color:#808080;">--zmq-pub tcp://127.0.0.1:18083 --enforce-dns-checkpointing --enable-dns-blocklist</span></ul><br>
|
||||
</ul>
|
||||
</td></tr></table>
|
||||
<br><br>
|
||||
|
||||
@@ -248,7 +248,7 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<ul>
|
||||
<li>Download the latest Monero <a href="https://www.getmonero.org/downloads/" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>18080</span> (Monero p2p port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 8 --in-peers 16</span> instead.
|
||||
<li>Wait until it's fully synchronized. If you didn't run Monero node before, it can take up to several days to synchronize (5-6 hours on a modern PC with fast SSD and fast Internet connection). You can add <span>--prune-blockchain</span> argument to the command line to run a pruned node (3-4 times less disk usage)
|
||||
</ul></details>
|
||||
@@ -304,7 +304,7 @@ P2Pool is a decentralized community, there is no dedicated support. You can reac
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get an error "monerod RPC ... is incompatible, update to RPC >= v3.8"</span>
|
||||
<ul><li>Use monerod v0.18.0.0 or newer</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get warnings "peer ... is ahead on mainchain (height ..., your height ...). Is your monerod stuck or lagging?"</span>
|
||||
<ul><li>Make sure you add these arguments to monerod command line: <span style="color:#808080;">--zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist</span></ul><br>
|
||||
<ul><li>Make sure you add these arguments to monerod command line: <span style="color:#808080;">--zmq-pub tcp://127.0.0.1:18083 --enforce-dns-checkpointing --enable-dns-blocklist</span></ul><br>
|
||||
</ul>
|
||||
</td></tr></table>
|
||||
<br><br>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 671 B |
@@ -0,0 +1,320 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>P2Pool nano - Decentralized Monero mining pool</title>
|
||||
<link rel="shortcut icon" type="image/png" href="favicon-32x32.png"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5">
|
||||
<style>
|
||||
a {
|
||||
color: #e09000;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #808080;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #383838;
|
||||
color: #e0e0e0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
table {
|
||||
color: #c0c0c0;
|
||||
border-spacing:15px 5px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
table.menu_page {
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
details > summary {
|
||||
padding: 0.25rem;
|
||||
font-size: 2.5rem;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
details > ul > li > span {
|
||||
color: #e09000;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function elapsedTimeStr(ts1, ts2, short_form) {
|
||||
let s = ts2 - ts1;
|
||||
if (s < 0) s = 0;
|
||||
let m = Math.floor(s / 60) % 60;
|
||||
let h = Math.floor(s / 3600) % 24;
|
||||
let d = Math.floor(s / 86400);
|
||||
if (short_form) {
|
||||
if (s >= 86400) return d + 'd';
|
||||
if (s >= 3600) return h + 'h';
|
||||
return m + 'm';
|
||||
}
|
||||
else {
|
||||
let result = m + 'm';
|
||||
if (s >= 3600) result = h + 'h ' + result;
|
||||
if (s >= 86400) result = d + 'd ' + h + 'h';
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function set_effort(el, value) {
|
||||
el.innerHTML = value.toFixed(2) + '%';
|
||||
el.style = (value < 100.0) ? "color:#00C000;" : (value < 200.0) ? "color:#E0E000;" : "color:#FF0000;";
|
||||
}
|
||||
|
||||
async function load_data() {
|
||||
init_menu();
|
||||
window.onresize = init_menu;
|
||||
|
||||
let pool_stats_req = await fetch('api/pool/stats');
|
||||
let pool_blocks_req = await fetch('api/pool/blocks');
|
||||
let network_stats_req = await fetch('api/network/stats');
|
||||
let latest_release_req = await fetch('api/latest_release');
|
||||
|
||||
let pool_stats = JSON.parse(await pool_stats_req.text());
|
||||
let pool_blocks = JSON.parse(await pool_blocks_req.text());
|
||||
let network_stats = JSON.parse(await network_stats_req.text());
|
||||
let latest_release = JSON.parse(await latest_release_req.text());
|
||||
|
||||
let pool_hashrate = pool_stats.pool_statistics.hashRate / 1e6;
|
||||
let pplns_duration = pool_stats.pool_statistics.pplnsWeight / pool_stats.pool_statistics.hashRate;
|
||||
let min_payout = 0.6 * pool_stats.pool_statistics.sidechainDifficulty / pool_stats.pool_statistics.pplnsWeight;
|
||||
|
||||
document.getElementById("pool_hashrate").innerHTML = pool_hashrate.toFixed(3) + ' MH/s';
|
||||
document.getElementById("pplns_duration").innerHTML = elapsedTimeStr(0, pplns_duration, 0) + ' ' + Math.floor(pplns_duration % 60) + 's';
|
||||
document.getElementById("pool_miners").innerHTML = pool_stats.pool_statistics.miners;
|
||||
document.getElementById("min_payout").innerHTML = min_payout.toFixed(5) + ' XMR';
|
||||
document.getElementById("latest_release").innerHTML = '<a href="' + latest_release.html_url + '" target="_blank">' + latest_release.name + '</a>';
|
||||
|
||||
let ts = Math.floor(Date.now() / 1000);
|
||||
|
||||
let n = pool_stats.pool_statistics.lastBlockFound;
|
||||
document.getElementById("pool_last_block").innerHTML = n ? ('<a href="/explorer/block/' + n + '" target="_blank">' + n + '</a> (' + elapsedTimeStr(pool_stats.pool_statistics.lastBlockFoundTime, ts, 0) + ' ago)') : 'N/A';
|
||||
document.getElementById("pool_total_blocks").innerHTML = pool_stats.pool_statistics.totalBlocksFound;
|
||||
|
||||
let t = document.getElementById('menu_blocks');
|
||||
let cur_effort = (pool_stats.pool_statistics.totalHashes - ((pool_blocks.length > 0) ? pool_blocks[0].totalHashes : 0)) * 100.0 / network_stats.difficulty;
|
||||
set_effort(document.getElementById("current_effort"), (cur_effort >= 0) ? cur_effort : 0);
|
||||
let total_effort = 0.0;
|
||||
let num_blocks_with_effort = 0;
|
||||
for (let i = 0, m = Math.min(pool_blocks.length, 50); i < m; ++i) {
|
||||
if (t.rows.length <= i + 1) t.insertRow(-1);
|
||||
let row = t.rows[i + 1];
|
||||
while (row.cells.length < 3) row.insertCell(-1);
|
||||
|
||||
let height = row.cells[0];
|
||||
let effort = row.cells[1];
|
||||
let age = row.cells[2];
|
||||
|
||||
n = pool_blocks[i].height;
|
||||
height.innerHTML = '<a href="/explorer/block/' + pool_blocks[i].hash + '" target="_blank">' + n + '</a>';
|
||||
|
||||
let value = 0.0;
|
||||
|
||||
if ((i + 1 < pool_blocks.length) && (pool_blocks[i + 1].totalHashes > 0)) {
|
||||
value = (pool_blocks[i].totalHashes - pool_blocks[i + 1].totalHashes) * 100.0 / pool_blocks[i].difficulty;
|
||||
}
|
||||
else {
|
||||
value = pool_blocks[i].totalHashes * 100.0 / pool_blocks[i].difficulty;
|
||||
}
|
||||
|
||||
total_effort += value;
|
||||
++num_blocks_with_effort;
|
||||
set_effort(effort, value);
|
||||
|
||||
age.innerHTML = elapsedTimeStr(pool_blocks[i].ts, ts, 1);
|
||||
}
|
||||
if (num_blocks_with_effort > 0) {
|
||||
let average_effort = total_effort / num_blocks_with_effort;
|
||||
set_effort(document.getElementById("average_effort"), average_effort);
|
||||
}
|
||||
|
||||
let network_hashrate = network_stats.difficulty / 120e6;
|
||||
document.getElementById("monero_hashrate").innerHTML = network_hashrate.toFixed(3) + ' MH/s';
|
||||
document.getElementById("monero_last_block").innerHTML = network_stats.height + ' (' + elapsedTimeStr(network_stats.timestamp, ts, 0) + ' ago)';
|
||||
}
|
||||
|
||||
const menu = ['pool', 'blocks', 'help', 'faq'];
|
||||
|
||||
function init_menu()
|
||||
{
|
||||
let is_mobile = false;
|
||||
|
||||
if (navigator.userAgentData) {
|
||||
is_mobile = navigator.userAgentData.mobile;
|
||||
}
|
||||
else {
|
||||
const mobile_preg = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i;
|
||||
is_mobile = mobile_preg.test(navigator.userAgent) || mobile_preg.test(navigator.platform);
|
||||
}
|
||||
|
||||
let e = document.getElementById('main_menu');
|
||||
|
||||
if (!is_mobile) {
|
||||
e.style.cursor = "pointer";
|
||||
document.querySelectorAll("details > summary").forEach(el => { el.style.cursor = "pointer"; });
|
||||
}
|
||||
|
||||
e.style.width = (window.innerWidth > 1600) ? "1600px" : "100%";
|
||||
|
||||
menu.forEach(element => {
|
||||
let e2 = document.getElementById('menu_' + element);
|
||||
e2.style.width = e.style.width;
|
||||
});
|
||||
}
|
||||
|
||||
function toggle_menu(name) {
|
||||
if (!name) {
|
||||
name = 'pool';
|
||||
}
|
||||
|
||||
menu.forEach(element => {
|
||||
let e = document.getElementById('menu_' + element);
|
||||
let b = document.getElementById('button_' + element);
|
||||
if (element == name) {
|
||||
e.style.display = 'block';
|
||||
b.style.backgroundColor = '#646464';
|
||||
window.location.hash = '#' + name;
|
||||
}
|
||||
else {
|
||||
e.style.display = 'none';
|
||||
b.style.backgroundColor = '#404040';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="load_data();setInterval(load_data, 2000);toggle_menu(window.location.hash.substr(1));">
|
||||
<div style="font-size:3rem;text-align:center;">P2Pool nano</div><div style="font-size:1.1rem;text-align:center;">Decentralized Monero mining pool</div>
|
||||
<div style="font-size:1rem;text-align:center;">Latest release: <span id="latest_release"><a href="https://github.com/SChernykh/p2pool/releases/latest" target="_blank">P2Pool</a></span></div>
|
||||
<br>
|
||||
<table id="main_menu" style="width:100%;margin-left:auto;margin-right:auto;table-layout:fixed;text-align:center;-ms-touch-action:none;touch-action:none;"><tr>
|
||||
<td onclick="toggle_menu('pool')" id="button_pool">Pool</td>
|
||||
<td onclick="toggle_menu('blocks')" id="button_blocks">Blocks</td>
|
||||
<td onclick="toggle_menu('help')" id="button_help">Get started</td>
|
||||
<td onclick="toggle_menu('faq')" id="button_faq">FAQ</td>
|
||||
</tr></table>
|
||||
<br>
|
||||
<table id="menu_pool" class="menu_page">
|
||||
<tr><td></td><td style="width:17rem;">Pool</td><td>Network</td></tr>
|
||||
<tr><td style="padding-bottom: 1rem;"></td><td></td><td></td></tr>
|
||||
<tr><td>Hashrate</td><td><span id="pool_hashrate">N/A</span></td><td><span id="monero_hashrate">N/A</span></td></tr>
|
||||
<tr><td>Miners</td><td><span id="pool_miners">N/A</span></td><td></td></tr>
|
||||
<tr><td>PPLNS window</td><td><span id="pplns_duration">N/A</span></td><td></td></tr>
|
||||
<tr><td>Last block</td><td><span id="pool_last_block">N/A</span></td><td><span id="monero_last_block">N/A</span></td></tr>
|
||||
<tr><td>Total blocks</td><td><span id="pool_total_blocks">N/A</span></td><td></td></tr>
|
||||
<tr><td>Current effort</td><td><span id="current_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td>Average effort<br><div style="text-align:center;font-size:0.9rem">last 50 blocks</div></td><td><span id="average_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Fee</td><td>0%</td><td></td></tr>
|
||||
<tr><td>Min payout</td><td><span id="min_payout">0.00027 XMR</span></td><td></td></tr>
|
||||
<tr><td>Payout scheme</td><td><a href="https://en.wikipedia.org/wiki/Mining_pool#Pay-per-last-N-shares" target="_blank">PPLNS</a></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Statistics</td><td><a href="https://nano.p2pool.observer/" target="_blank">P2Pool observer</a></td><td></td></tr>
|
||||
</table>
|
||||
<table id="menu_blocks" class="menu_page">
|
||||
<tr><td style="padding-right:5rem;">Height</td><td style="padding-right:5rem;">Effort</td><td>Age</td></tr>
|
||||
</table>
|
||||
<table id="menu_help" class="menu_page"><tr><td>
|
||||
|
||||
<details><summary>P2Pool video guide</summary>
|
||||
<ul>
|
||||
<li>A detailed <a href="https://www.youtube.com/watch?v=NbxbRu-2GWI" target="_blank">video guide</a> to install P2Pool and start mining
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<details><summary>Setup Monero wallet</summary>
|
||||
Wallets with confirmed P2Pool support<br>
|
||||
<span style="font-size:0.9rem;color:#e09000;">You might not see P2Pool payouts in other wallets if they're not updated!</span>
|
||||
<ul>
|
||||
<li>Official <a href="https://www.getmonero.org/downloads/" target="_blank">Monero CLI and GUI v0.18.1.0</a> and newer
|
||||
<li><a href="https://play.google.com/store/apps/details?id=com.m2049r.xmrwallet" target="_blank">Monerujo v3.0.2 "Fluorine Fermi"</a> and newer
|
||||
<li><a href="https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet" target="_blank">Cake Wallet v4.4.5</a> and newer
|
||||
<li><a href="https://featherwallet.org/" target="_blank">Feather Wallet v2.1.0</a> and newer
|
||||
<li><a href="https://mymonero.com/" target="_blank">MyMonero</a>
|
||||
</ul>
|
||||
It's highly recommended to create a new wallet for mining because wallet addresses are public on p2pool. You have to use the primary wallet address for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
|
||||
</details>
|
||||
|
||||
<details><summary>Setup Monero node</summary>
|
||||
<ul>
|
||||
<li>Download the latest Monero <a href="https://www.getmonero.org/downloads/" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>18080</span> (Monero p2p port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --enforce-dns-checkpointing --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 8 --in-peers 16</span> instead.
|
||||
<li>Wait until it's fully synchronized. If you didn't run Monero node before, it can take up to several days to synchronize (5-6 hours on a modern PC with fast SSD and fast Internet connection). You can add <span>--prune-blockchain</span> argument to the command line to run a pruned node (3-4 times less disk usage)
|
||||
</ul></details>
|
||||
|
||||
<details><summary>Setup P2Pool node</summary>
|
||||
<ul>
|
||||
<li>Download the latest P2Pool <a href="https://github.com/SChernykh/p2pool/releases/latest" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>37889</span> (P2Pool port) or <span>37890</span> (P2Pool nano port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./p2pool --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS --nano</span>
|
||||
<li>It should take no more than 5-10 minutes to synchronize
|
||||
</ul></details>
|
||||
|
||||
<details><summary>Miner software</summary>
|
||||
<ul>
|
||||
<li><a href="https://xmrig.com/" target="_blank">XMRig</a> is recommended. <a href="https://xmrig.com/proxy" target="_blank">XMRig Proxy</a> is fully supported.
|
||||
<li>Once P2Pool sync is complete, XMRig should be able to connect to the stratum server on port <span>3333</span>
|
||||
<li>Run <span>./xmrig -o 127.0.0.1:3333</span>. Note that you don't need to specify wallet address for xmrig. Wallet address set in xmrig config will be ignored!
|
||||
<li>To set custom fixed difficulty for your miner (for example, <span>10000</span>), run <span>./xmrig -u x+10000 -o 127.0.0.1:3333</span>
|
||||
<li>To connect another mining rig to your P2Pool node, run <span>./xmrig -o YOUR_P2POOL_NODE_IP:3333</span> on that mining rig
|
||||
</ul></details>
|
||||
|
||||
<details><summary>Checking your progress</summary>
|
||||
<ul>
|
||||
<li>You can enter your wallet address at <a href="https://p2pool.observer/" target="_blank">P2Pool Observer</a>
|
||||
<li>P2Pool Observer for P2Pool nano can be found <a href="https://nano.p2pool.observer/" target="_blank">here</a>
|
||||
<li>You will find your wallet's statistics there only after you've mined at least 1 P2Pool share
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<details><summary>Help and support</summary>
|
||||
P2Pool is a decentralized community, there is no dedicated support. You can reach and get help from other miners on:
|
||||
<ul>
|
||||
<li>IRC channels: <span>#p2pool-log</span> (<span>#p2pool-mini</span> for P2Pool mini) on <a href="https://libera.chat/" target="_blank">Libera.Chat</a>
|
||||
<li>Reddit: <a href="https://reddit.com/r/MoneroMining/" target="_blank">r/MoneroMining</a>
|
||||
</ul></details>
|
||||
</td></tr></table>
|
||||
<table id="menu_faq" class="menu_page"><tr><td>
|
||||
<ul>
|
||||
<li><span style="font-size:2rem;color:#e09000;">What are system requirements to run P2Pool?</span>
|
||||
<ul><li>P2Pool needs 0.5 GB disc space and 2.6 GB RAM to run (0.6 GB RAM in light mode). Add this to monerod requirements if you run both on the same machine. Add <span style="color:#808080;">--light-mode</span> to p2pool command line to reduce the memory usage to 0.6 GB, or <span style="color:#808080;">--no-randomx --no-cache</span> to reduce the memory usage to less than 100 MB.</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">Does P2Pool work with XMRig Proxy?</span>
|
||||
<ul><li>Yes, P2Pool fully supports <a href="https://xmrig.com/proxy" target="_blank">XMRig Proxy</a>.</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">Does monerod have to be run on the same machine as P2Pool?</span>
|
||||
<ul><li>No, you can run them on different machines and even connect multiple p2pool instances to a single server running monerod</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">Does P2Pool work with pruned Monero node?</span>
|
||||
<ul><li>Yes, you can use pruned Monero node to mine on P2Pool</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">Does P2Pool require incoming connections to work properly?</span>
|
||||
<ul><li>P2Pool (and Monero) can work with only outgoing connections, but it's recommended to open ports 18080 (Monero) and 37889/37888/37890 (P2Pool/P2Pool mini/P2Pool nano) for better connectivity with the rest of the network.</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I have been mining for several hours and still got no rewards?</span>
|
||||
<ul><li>P2Pool doesn't work exactly like regular pools - there's no "pending balance" here. You need to find a pool share first and then wait for P2Pool to find a Monero block. You'll get a payout to your XMR wallet as soon as a block is found and you have shares in PPLNS window. It can take several days to a week to find a share if your hashrate is low. Type "status" command in P2Pool console or visit <a href="https://nano.p2pool.observer/" target="_blank">P2Pool observer</a> to check your progress.</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I am mining but I can't find any shares</span>
|
||||
<ul><li>First check for any warnings and errors in P2Pool console and logs. If everything works fine, you can check the <a href="https://p2pool.observer/calculate-share-time" target="_blank">average share time calculator</a> to get an idea how often you should find a share with your hashrate. If this time is more than 1 day, it's recommended to switch to P2Pool mini or P2Pool nano by adding <span style="color:#808080;">--mini</span> or <span style="color:#808080;">--nano</span> to P2Pool command line.</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get an error "monerod RPC ... is incompatible, update to RPC >= v3.8"</span>
|
||||
<ul><li>Use monerod v0.18.0.0 or newer</ul><br>
|
||||
<li><span style="font-size:2rem;color:#e09000;">I get warnings "peer ... is ahead on mainchain (height ..., your height ...). Is your monerod stuck or lagging?"</span>
|
||||
<ul><li>Make sure you add these arguments to monerod command line: <span style="color:#808080;">--zmq-pub tcp://127.0.0.1:18083 --enforce-dns-checkpointing --enable-dns-blocklist</span></ul><br>
|
||||
</ul>
|
||||
</td></tr></table>
|
||||
<br><br>
|
||||
<div style="position:fixed;width:100%;bottom:0;background-color:#383838;font-size:1rem;text-align:center;color:#b0b0b0;">
|
||||
<a href="api/" target="_blank">Pool API</a> | <a href="https://github.com/SChernykh/p2pool" target="_blank">Source</a> | <a href="http://yucmgsbw7nknw7oi3bkuwudvc657g2xcqahhbjyewazusyytapqo4xid.onion/nano/" target="_blank">Onion URL</a><br>
|
||||
Donate to support the project:<br><span style="font-size:0.9rem;color:#b0b0b0;">44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg</span><br>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -106,11 +106,11 @@ mkdir build && cd build
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
echo "Installing GCC 15.1.0"
|
||||
echo "Installing GCC 15.2.0"
|
||||
|
||||
cd /root
|
||||
|
||||
git clone --depth 1 --branch releases/gcc-15.1.0 --jobs $(nproc) git://gcc.gnu.org/git/gcc.git gcc-15
|
||||
git clone --depth 1 --branch releases/gcc-15.2.0 --jobs $(nproc) git://gcc.gnu.org/git/gcc.git gcc-15
|
||||
|
||||
cd gcc-15
|
||||
contrib/download_prerequisites
|
||||
|
||||
@@ -3,26 +3,26 @@ set -e
|
||||
|
||||
# Software versions to install
|
||||
|
||||
_7ZIP_VERSION=2409
|
||||
BINUTILS_VERSION=2_44
|
||||
_7ZIP_VERSION=2501
|
||||
BINUTILS_VERSION=2_45
|
||||
CLANG_VERSION=20.1.8
|
||||
CMAKE_VERSION=4.0.3
|
||||
CMAKE_VERSION=4.1.1
|
||||
FREEBSD_VERSION=12.4
|
||||
GCC_VERSION=15.1.0
|
||||
GLIBC_VERSION=2.41
|
||||
LINUX_HEADERS_VERSION=6.15.4
|
||||
GCC_VERSION=15.2.0
|
||||
GLIBC_VERSION=2.42
|
||||
LINUX_HEADERS_VERSION=6.16.3
|
||||
MACOSX_SDK_VERSION=15.5
|
||||
MAKE_VERSION=4.4.1
|
||||
MINGW_VERSION=13.0.0
|
||||
XZ_VERSION=5.8.1
|
||||
TAR_VERSION=1.35
|
||||
|
||||
_7ZIP_SHA256="914c7e20ad5ef8e4d3cf08620ff8894b28fe11b7eb99809d6930870fbe48a281"
|
||||
CMAKE_SHA256="585ae9e013107bc8e7c7c9ce872cbdcbdff569e675b07ef57aacfb88c886faac"
|
||||
_7ZIP_SHA256="4ca3b7c6f2f67866b92622818b58233dc70367be2f36b498eb0bdeaaa44b53f4"
|
||||
CMAKE_SHA256="5a6c61cb62b38e153148a2c8d4af7b3d387f0c8c32b6dbceb5eb4af113efd65a"
|
||||
FREEBSD_AARCH64_SHA256="6c401819bfb93e810c9f9aa670a1e4685f924df5e7e0c9c6397dd6c16c954fa2"
|
||||
FREEBSD_X86_64_SHA256="581c7edacfd2fca2bdf5791f667402d22fccd8a5e184635e0cac075564d57aa8"
|
||||
GLIBC_SHA256="a5a26b22f545d6b7d7b3dd828e11e428f24f4fac43c934fb071b6a7d0828e901"
|
||||
HEADERS_SHA256="0eafd627b602f58d73917d00e4fc3196ba18cba67df6995a42aa74744d8efa16"
|
||||
GLIBC_SHA256="d1775e32e4628e64ef930f435b67bb63af7599acb6be2b335b9f19f16509f17f"
|
||||
HEADERS_SHA256="80439ba055c12f541abf44b8fc3c9b825a8f42fc25ce67462ec7e556c5790b85"
|
||||
MACOSX_SDK_SHA256="c15cf0f3f17d714d1aa5a642da8e118db53d79429eb015771ba816aa7c6c1cbd"
|
||||
MAKE_SHA256="dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3"
|
||||
TAR_SHA256="4d62ff37342ec7aed748535323930c7cf94acf71c3591882b26a7ea50f3edc16"
|
||||
@@ -114,7 +114,7 @@ fi
|
||||
|
||||
tar xvf $CMAKE_FILE
|
||||
cp $CMAKE_NAME/bin/* /usr/local/bin
|
||||
cp -r $CMAKE_NAME/share/cmake-4.0 /usr/local/share
|
||||
cp -r $CMAKE_NAME/share/cmake-4.1 /usr/local/share
|
||||
|
||||
echo "Install make"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ flags_datetime="-D__DATE__=\"\\\"$CURRENT_DATE\\\"\" -D__TIME__=\"\\\"$CURRENT_T
|
||||
flags_libs="--target=x86_64-pc-windows-gnu -Os -flto -Wl,/timestamp:$BUILD_TIMESTAMP -fuse-ld=lld -w $flags_size $flags_datetime"
|
||||
|
||||
flags_p2pool="--target=x86_64-pc-windows-gnu -Wl,/timestamp:$BUILD_TIMESTAMP -fuse-ld=lld -femulated-tls -Wno-unused-command-line-argument -Wno-unknown-attributes $flags_size $flags_datetime"
|
||||
flags_cxx_headers="-isystem /usr/local/x86_64-w64-mingw32/include/c++ -isystem /usr/local/x86_64-w64-mingw32/include/c++/15.1.0 -isystem /usr/local/x86_64-w64-mingw32/include"
|
||||
flags_cxx_headers="-isystem /usr/local/x86_64-w64-mingw32/include/c++ -isystem /usr/local/x86_64-w64-mingw32/include/c++/15.2.0 -isystem /usr/local/x86_64-w64-mingw32/include"
|
||||
|
||||
cd /p2pool
|
||||
git apply --verbose --ignore-whitespace --directory=external/src/grpc/third_party/boringssl-with-bazel patches/boringssl/win7.patch
|
||||
|
||||
@@ -166,6 +166,14 @@ struct alignas(uint64_t) hash
|
||||
|
||||
FORCEINLINE hash() : h{} {}
|
||||
|
||||
constexpr hash(std::initializer_list<uint8_t> l) : h{} {
|
||||
auto it = l.begin();
|
||||
|
||||
for (size_t i = 0; (i < HASH_SIZE) && (it != l.end()); ++i, ++it) {
|
||||
h[i] = *it;
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE bool operator<(const hash& other) const
|
||||
{
|
||||
const uint64_t* a = u64();
|
||||
@@ -496,6 +504,14 @@ struct raw_ip
|
||||
|
||||
static_assert(sizeof(raw_ip) == 16, "struct raw_ip has invalid size");
|
||||
|
||||
struct MoneroBlockBroadcastHeader
|
||||
{
|
||||
uint32_t header_size;
|
||||
uint32_t miner_tx_size;
|
||||
};
|
||||
|
||||
static_assert(sizeof(MoneroBlockBroadcastHeader) == sizeof(uint32_t) * 2, "struct MoneroBlockBroadcastHeader has invalid size");
|
||||
|
||||
void* malloc_hook(size_t n) noexcept;
|
||||
void* realloc_hook(void* ptr, size_t size) noexcept;
|
||||
void* calloc_hook(size_t count, size_t size) noexcept;
|
||||
|
||||
@@ -57,6 +57,7 @@ struct parse_wrapper<T, out_type> \
|
||||
JSON_VALUE_PARSER(String, const char*)
|
||||
JSON_VALUE_PARSER(String, std::string)
|
||||
JSON_VALUE_PARSER(Uint, uint8_t)
|
||||
JSON_VALUE_PARSER(Uint, uint32_t)
|
||||
JSON_VALUE_PARSER(Uint64, uint64_t)
|
||||
JSON_VALUE_PARSER(Bool, bool)
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ void CurlContext::shutdown()
|
||||
void Call(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, bool ssl, const std::string& ssl_fingerprint, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop)
|
||||
{
|
||||
if (!loop) {
|
||||
loop = uv_default_loop();
|
||||
loop = uv_default_loop_checked();
|
||||
}
|
||||
|
||||
const bool result = CallOnLoop(loop,
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
namespace p2pool {
|
||||
namespace JSONRPCRequest {
|
||||
|
||||
typedef Callback<void, const char*, size_t, double>::Base CallbackBase;
|
||||
typedef Callback<void, const char* /*msg*/, size_t /*msg_size*/, double /*tcp_ping*/>::Base CallbackBase;
|
||||
|
||||
FORCEINLINE static constexpr void dummy_callback(const char* /*msg*/, size_t /*msg_size*/, double /*tcp_ping*/) {}
|
||||
|
||||
void Call(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, bool ssl, const std::string& ssl_fingerprint, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop);
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ enum KeccakParams {
|
||||
|
||||
extern const uint64_t keccakf_rndc[24];
|
||||
|
||||
// keccak hash of a single 0x00 byte
|
||||
constexpr hash keccak_0x00{ 0xbc, 0x36, 0x78, 0x9e, 0x7a, 0x1e, 0x28, 0x14, 0x36, 0x46, 0x42, 0x29, 0x82, 0x8f, 0x81, 0x7d, 0x66, 0x12, 0xf7, 0xb4, 0x77, 0xd6, 0x65, 0x91, 0xff, 0x96, 0xa9, 0xe0, 0x64, 0xbc, 0xc9, 0x8a };
|
||||
|
||||
typedef void (*keccakf_func)(std::array<uint64_t, 25>&);
|
||||
extern keccakf_func keccakf;
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ void p2pool_usage()
|
||||
"--rpc-ssl-fingerprint base64-encoded fingerprint of the Monero node's certificate (optional, use it for certificate pinning)\n"
|
||||
#endif
|
||||
"--no-stratum-http Disable HTTP on Stratum ports\n"
|
||||
"--full-validation Enables full share validation / increases CPU usage\n"
|
||||
"--help Show this help message\n\n"
|
||||
"Example command line:\n\n"
|
||||
"%s --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:%d --p2p 0.0.0.0:%d\n\n",
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "p2pool.h"
|
||||
#include "params.h"
|
||||
#include "keccak.h"
|
||||
#include "merkle.h"
|
||||
#include "pow_hash.h"
|
||||
#include "side_chain.h"
|
||||
#include "pool_block.h"
|
||||
#include "block_cache.h"
|
||||
@@ -79,6 +81,7 @@ P2PServer::P2PServer(p2pool* pool)
|
||||
m_blockDeserializeBuf.reserve(MAX_BLOCK_SIZE);
|
||||
|
||||
m_auxJobMessages.reserve(1024);
|
||||
m_MoneroBlockBroadcasts.reserve(1024);
|
||||
|
||||
// Diffuse the initial state in case it has low quality
|
||||
m_rng.discard(10000);
|
||||
@@ -130,6 +133,16 @@ P2PServer::P2PServer(p2pool* pool)
|
||||
m_AuxJobBroadcastAsync.data = this;
|
||||
#endif
|
||||
|
||||
uv_mutex_init_checked(&m_MoneroBlockBroadcastsLock);
|
||||
uv_mutex_init_checked(&m_MoneroBlocksToBroadcastLock);
|
||||
|
||||
err = uv_async_init(&m_loop, &m_MoneroBlocksToBroadcastAsync, on_monero_block_broadcast);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
m_MoneroBlocksToBroadcastAsync.data = this;
|
||||
|
||||
err = uv_timer_init(&m_loop, &m_timer);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create timer, error " << uv_err_name(err));
|
||||
@@ -171,6 +184,9 @@ P2PServer::~P2PServer()
|
||||
uv_mutex_destroy(&m_AuxJobBroadcastLock);
|
||||
#endif
|
||||
|
||||
uv_mutex_destroy(&m_MoneroBlockBroadcastsLock);
|
||||
uv_mutex_destroy(&m_MoneroBlocksToBroadcastLock);
|
||||
|
||||
delete m_block;
|
||||
delete m_cache;
|
||||
|
||||
@@ -1104,6 +1120,7 @@ void P2PServer::show_peers() const
|
||||
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;
|
||||
case PROTOCOL_VERSION_1_4: s << " p1.4"; break;
|
||||
default: s << " p?"; break;
|
||||
}
|
||||
}
|
||||
@@ -1178,6 +1195,7 @@ void P2PServer::on_timer()
|
||||
check_for_updates();
|
||||
api_update_local_stats();
|
||||
clean_aux_job_messages();
|
||||
clean_monero_block_broadcasts();
|
||||
}
|
||||
|
||||
void P2PServer::flush_cache()
|
||||
@@ -1427,6 +1445,11 @@ void P2PServer::on_shutdown()
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_AuxJobBroadcastAsync), nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
MutexLock lock(m_MoneroBlocksToBroadcastLock);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_MoneroBlocksToBroadcastAsync), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::api_update_local_stats()
|
||||
@@ -1588,6 +1611,149 @@ void P2PServer::clean_aux_job_messages()
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::clean_monero_block_broadcasts()
|
||||
{
|
||||
if ((m_timerCounter & 255) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
MutexLock lock(m_MoneroBlockBroadcastsLock);
|
||||
|
||||
if (m_MoneroBlockBroadcasts.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
|
||||
for (auto it = m_MoneroBlockBroadcasts.begin(); it != m_MoneroBlockBroadcasts.end();) {
|
||||
if (cur_time > it->second + MONERO_BROADCAST_TIMEOUT) {
|
||||
it = m_MoneroBlockBroadcasts.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::submit_monero_blocks()
|
||||
{
|
||||
if (m_MoneroBlocksToSubmit.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOGINFO(6, "submit_monero_blocks: started, queue size = " << m_MoneroBlocksToSubmit.size());
|
||||
|
||||
const Params::Host& host = m_pool->current_host();
|
||||
|
||||
JSONRPCRequest::call(
|
||||
host.m_address,
|
||||
host.m_rpcPort,
|
||||
m_MoneroBlocksToSubmit.front(),
|
||||
host.m_rpcLogin,
|
||||
m_socks5Proxy,
|
||||
host.m_rpcSSL,
|
||||
host.m_rpcSSL_Fingerprint,
|
||||
JSONRPCRequest::dummy_callback,
|
||||
[this](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(3, "on_monero_block_broadcast: submit_block RPC request failed, error " << log::const_buf(data, size));
|
||||
}
|
||||
|
||||
if (!m_MoneroBlocksToSubmit.empty()) {
|
||||
m_MoneroBlocksToSubmit.pop_front();
|
||||
}
|
||||
LOGINFO(6, "submit_monero_blocks: finished, queue size = " << m_MoneroBlocksToSubmit.size());
|
||||
|
||||
submit_monero_blocks();
|
||||
},
|
||||
&m_loop
|
||||
);
|
||||
}
|
||||
|
||||
void P2PServer::broadcast_monero_block_async(std::vector<std::vector<uint8_t>>&& blobs)
|
||||
{
|
||||
MutexLock lock(m_MoneroBlocksToBroadcastLock);
|
||||
|
||||
m_MoneroBlocksToBroadcast = std::move(blobs);
|
||||
|
||||
const int err = uv_async_send(&m_MoneroBlocksToBroadcastAsync);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_send failed, error " << uv_err_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::broadcast_monero_block_handler()
|
||||
{
|
||||
std::vector<std::vector<uint8_t>> blobs;
|
||||
{
|
||||
MutexLock lock(m_MoneroBlocksToBroadcastLock);
|
||||
blobs = std::move(m_MoneroBlocksToBroadcast);
|
||||
}
|
||||
|
||||
for (const std::vector<uint8_t>& blob : blobs) {
|
||||
if (!blob.empty()) {
|
||||
broadcast_monero_block(blob.data(), static_cast<uint32_t>(blob.size()), nullptr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::broadcast_monero_block(const uint8_t* data, uint32_t data_size, const P2PClient* source, bool duplicate_check_done)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
if (data_size < sizeof(MoneroBlockBroadcastHeader)) {
|
||||
LOGWARN(3, "broadcast_monero_block: data_size is too small: " << data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!duplicate_check_done && !store_monero_block_broadcast(data + sizeof(MoneroBlockBroadcastHeader), data_size - sizeof(MoneroBlockBroadcastHeader))) {
|
||||
LOGINFO(6, "broadcast_monero_block: skipping duplicate broadcast");
|
||||
return;
|
||||
}
|
||||
|
||||
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_4)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool result = send(client, [client, data, data_size](uint8_t* buf, size_t buf_size) -> size_t {
|
||||
LOGINFO(6, "sending MONERO_BLOCK_BROADCAST 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::MONERO_BLOCK_BROADCAST);
|
||||
|
||||
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 MONERO_BLOCK_BROADCAST to " << static_cast<char*>(client->m_addrString) << ", disconnecting");
|
||||
client->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool P2PServer::store_monero_block_broadcast(const uint8_t* data, uint32_t data_size)
|
||||
{
|
||||
hash digest;
|
||||
sha256(data, data_size, digest.h);
|
||||
|
||||
// Every message can be received from multiple peers, so broadcast it only once
|
||||
MutexLock lock(m_MoneroBlockBroadcastsLock);
|
||||
return m_MoneroBlockBroadcasts.emplace(*digest.u64(), seconds_since_epoch()).second;
|
||||
}
|
||||
|
||||
P2PServer::P2PClient::~P2PClient()
|
||||
{
|
||||
}
|
||||
@@ -1901,6 +2067,23 @@ bool P2PServer::P2PClient::on_read(const char* data, uint32_t size)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageId::MONERO_BLOCK_BROADCAST:
|
||||
LOGINFO(6, "peer " << log::Gray() << static_cast<char*>(m_addrString) << log::NoColor() << " sent MONERO_BLOCK_BROADCAST (" << bytes_left << " bytes in the buffer)");
|
||||
|
||||
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_monero_block_broadcast(buf + 1 + sizeof(uint32_t), msg_size)) {
|
||||
ban(DEFAULT_BAN_TIME);
|
||||
server->remove_peer_from_list(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_read) {
|
||||
@@ -2822,6 +3005,147 @@ bool P2PServer::P2PClient::on_aux_job_donation(const uint8_t* buf, uint32_t size
|
||||
return true;
|
||||
}
|
||||
|
||||
bool P2PServer::P2PClient::on_monero_block_broadcast(const uint8_t* buf, uint32_t size) const
|
||||
{
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
|
||||
if (size < sizeof(MoneroBlockBroadcastHeader)) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST size: " << size);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* buf0 = buf;
|
||||
uint32_t size0 = size;
|
||||
|
||||
MoneroBlockBroadcastHeader data;
|
||||
memcpy(&data, buf, sizeof(data));
|
||||
|
||||
buf += sizeof(data);
|
||||
size -= sizeof(data);
|
||||
|
||||
const uint64_t header_and_miner_tx_size = static_cast<uint64_t>(data.header_size) + data.miner_tx_size;
|
||||
|
||||
if ((data.header_size < 43) || (data.header_size > 128) || (data.miner_tx_size < 64) || (header_and_miner_tx_size >= size)) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST header: " << data.header_size << ", " << data.miner_tx_size << ", " << size);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t num_transactions;
|
||||
const uint8_t* tx_hashes = readVarint(buf + header_and_miner_tx_size, buf + size, num_transactions);
|
||||
if (!tx_hashes) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: tx_hashes not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((num_transactions >= MAX_BLOCK_SIZE / HASH_SIZE) || (num_transactions * HASH_SIZE != size - static_cast<uint32_t>(tx_hashes - buf))) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: invalid number of transactions " << num_transactions);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf[data.header_size] != TX_VERSION) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: TX_VERSION byte not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t unlock_height;
|
||||
if (!readVarint(buf + data.header_size + 1, buf + header_and_miner_tx_size, unlock_height)) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: unlock_height not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
p2pool* pool = server->m_pool;
|
||||
|
||||
// Ignore blocks which already unlocked
|
||||
const MinerData miner_data = pool->miner_data();
|
||||
const uint64_t cur_height = miner_data.height;
|
||||
|
||||
if (unlock_height < cur_height) {
|
||||
LOGINFO(5, "Outdated MONERO_BLOCK_BROADCAST: unlock_height = " << unlock_height << ", current height = " << cur_height << " - ignored");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ignore repeated old messages
|
||||
if (!server->store_monero_block_broadcast(buf, size)) {
|
||||
LOGINFO(6, "Repeated MONERO_BLOCK_BROADCAST - ignored");
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t height = unlock_height - MINER_REWARD_UNLOCK_TIME;
|
||||
LOGINFO(6, "on_monero_block_broadcast: height = " << height);
|
||||
|
||||
difficulty_type diff;
|
||||
if (!pool->get_difficulty_at_height(height, diff)) {
|
||||
LOGWARN(3, "MONERO_BLOCK_BROADCAST: couldn't get difficulty at height " << height);
|
||||
diff = miner_data.difficulty;
|
||||
}
|
||||
|
||||
// Use 90% of this height's difficulty to account for possible altchain deviations
|
||||
diff -= diff / 10;
|
||||
|
||||
hash seed;
|
||||
if (!pool->get_seed(height, seed)) {
|
||||
LOGWARN(3, "MONERO_BLOCK_BROADCAST: couldn't get seed for height " << height);
|
||||
return true;
|
||||
}
|
||||
|
||||
hash hashes[3] = { {}, keccak_0x00, {} };
|
||||
|
||||
// "miner_tx_size - 1" because the last byte is 0x00 (base rct data), it goes into the second hash
|
||||
keccak(buf + data.header_size, static_cast<int>(data.miner_tx_size) - 1, hashes[0].h);
|
||||
|
||||
std::vector<hash> transactions(num_transactions + 1);
|
||||
keccak(reinterpret_cast<uint8_t*>(hashes), sizeof(hashes), transactions[0].h);
|
||||
|
||||
if (num_transactions > 0) {
|
||||
memcpy(transactions.data() + 1, tx_hashes, num_transactions * HASH_SIZE);
|
||||
}
|
||||
|
||||
root_hash root;
|
||||
merkle_hash(transactions, root);
|
||||
|
||||
std::vector<uint8_t> blob;
|
||||
blob.reserve(data.header_size + HASH_SIZE + 2);
|
||||
|
||||
blob.insert(blob.end(), buf, buf + data.header_size);
|
||||
blob.insert(blob.end(), root.h, root.h + HASH_SIZE);
|
||||
writeVarint(num_transactions + 1, blob);
|
||||
|
||||
hash pow_hash;
|
||||
if (!pool->hasher()->calculate(blob.data(), blob.size(), height, seed, pow_hash, false)) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: failed to calculate PoW hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!diff.check_pow(pow_hash)) {
|
||||
LOGWARN(3, "Invalid MONERO_BLOCK_BROADCAST: diff check failed, PoW hash = " << pow_hash);
|
||||
return false;
|
||||
}
|
||||
|
||||
server->broadcast_monero_block(buf0, size0, this, true);
|
||||
|
||||
std::string request;
|
||||
request.reserve(size * 2 + 128);
|
||||
|
||||
request.append("{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"submit_block\",\"params\":[\"");
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
request.append(1, "0123456789abcdef"[buf[i] >> 4]);
|
||||
request.append(1, "0123456789abcdef"[buf[i] & 15]);
|
||||
}
|
||||
|
||||
request.append("\"]}");
|
||||
|
||||
server->m_MoneroBlocksToSubmit.emplace_back(std::move(request));
|
||||
|
||||
// Kick the JSON RPC request loop only when the first request arrives
|
||||
// The other requests will be queued and submit_monero_blocks() will process them one by one
|
||||
if (server->m_MoneroBlocksToSubmit.size() == 1) {
|
||||
server->submit_monero_blocks();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool P2PServer::P2PClient::handle_incoming_block_async(const PoolBlock* block, uint64_t max_time_delta)
|
||||
{
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
|
||||
+28
-2
@@ -40,8 +40,9 @@ 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 PROTOCOL_VERSION_1_4 = 0x00010004UL;
|
||||
|
||||
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_3;
|
||||
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_4;
|
||||
|
||||
class P2PServer : public TCPServer
|
||||
{
|
||||
@@ -59,7 +60,9 @@ public:
|
||||
BLOCK_NOTIFY,
|
||||
// Donation messages are signed by author's private keys to prevent their abuse/misuse.
|
||||
AUX_JOB_DONATION,
|
||||
LAST = AUX_JOB_DONATION,
|
||||
// Broadcast 3rd-party Monero blocks to make the whole Monero network faster
|
||||
MONERO_BLOCK_BROADCAST,
|
||||
LAST = MONERO_BLOCK_BROADCAST,
|
||||
};
|
||||
|
||||
explicit P2PServer(p2pool *pool);
|
||||
@@ -118,6 +121,7 @@ public:
|
||||
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 on_monero_block_broadcast(const uint8_t* buf, uint32_t size) const;
|
||||
|
||||
[[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);
|
||||
@@ -212,6 +216,12 @@ public:
|
||||
|
||||
void broadcast_aux_job_donation(const uint8_t* data, uint32_t data_size, uint64_t timestamp, const P2PClient* source, bool duplicate_check_done);
|
||||
|
||||
void broadcast_monero_block_async(std::vector<std::vector<uint8_t>>&& blobs);
|
||||
void broadcast_monero_block_handler();
|
||||
void broadcast_monero_block(const uint8_t* data, uint32_t data_size, const P2PClient* source, bool duplicate_check_done);
|
||||
|
||||
bool store_monero_block_broadcast(const uint8_t* data, uint32_t data_size);
|
||||
|
||||
private:
|
||||
[[nodiscard]] const char* get_log_category() const override;
|
||||
|
||||
@@ -307,12 +317,16 @@ private:
|
||||
|
||||
enum {
|
||||
AUX_JOB_TIMEOUT = 3600,
|
||||
MONERO_BROADCAST_TIMEOUT = 3600 * 6,
|
||||
};
|
||||
|
||||
unordered_set<std::pair<uint64_t, uint64_t>> m_auxJobMessages;
|
||||
std::vector<uint8_t> m_auxJobLastMessage;
|
||||
uint64_t m_auxJobLastMessageTimestamp;
|
||||
|
||||
uv_mutex_t m_MoneroBlockBroadcastsLock;
|
||||
unordered_map<uint64_t, uint64_t> m_MoneroBlockBroadcasts;
|
||||
|
||||
void send_aux_job_donation(P2PServer::P2PClient* client, const uint8_t* data, uint32_t data_size);
|
||||
|
||||
void clean_aux_job_messages();
|
||||
@@ -332,6 +346,18 @@ private:
|
||||
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
|
||||
|
||||
uv_mutex_t m_MoneroBlocksToBroadcastLock;
|
||||
std::vector<std::vector<uint8_t>> m_MoneroBlocksToBroadcast;
|
||||
|
||||
uv_async_t m_MoneroBlocksToBroadcastAsync;
|
||||
|
||||
std::deque<std::string> m_MoneroBlocksToSubmit;
|
||||
|
||||
static void on_monero_block_broadcast(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->broadcast_monero_block_handler(); }
|
||||
|
||||
void clean_monero_block_broadcasts();
|
||||
void submit_monero_blocks();
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+77
-20
@@ -158,6 +158,13 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
}
|
||||
m_reconnectToHostAsync.data = this;
|
||||
|
||||
err = uv_async_init(uv_default_loop_checked(), &m_getMissingHeightsAsync, on_get_missing_heights);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
m_getMissingHeightsAsync.data = this;
|
||||
|
||||
uv_rwlock_init_checked(&m_mainchainLock);
|
||||
uv_rwlock_init_checked(&m_minerDataLock);
|
||||
#ifndef P2POOL_UNIT_TESTS
|
||||
@@ -179,6 +186,8 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
uv_mutex_init_checked(&m_submitBlockDataLock);
|
||||
uv_mutex_init_checked(&m_submitAuxBlockDataLock);
|
||||
|
||||
uv_mutex_init_checked(&m_missingHeightsLock);
|
||||
|
||||
m_api = p->m_apiPath.empty() ? nullptr : new p2pool_api(p->m_apiPath, p->m_localStats);
|
||||
|
||||
if (p->m_localStats && !m_api) {
|
||||
@@ -264,6 +273,8 @@ p2pool::~p2pool()
|
||||
uv_mutex_destroy(&m_submitBlockDataLock);
|
||||
uv_mutex_destroy(&m_submitAuxBlockDataLock);
|
||||
|
||||
uv_mutex_destroy(&m_missingHeightsLock);
|
||||
|
||||
delete m_api;
|
||||
delete m_sideChain;
|
||||
delete m_hasher;
|
||||
@@ -497,31 +508,64 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
missing_heights.erase(std::unique(missing_heights.begin(), missing_heights.end()), missing_heights.end());
|
||||
}
|
||||
|
||||
for (uint64_t h : missing_heights) {
|
||||
LOGWARN(3, "Mainchain data for height " << h << " is missing, requesting it from monerod again");
|
||||
MutexLock lock(m_missingHeightsLock);
|
||||
m_missingHeights = std::move(missing_heights);
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1] = {};
|
||||
log::Stream s(buf);
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << h << "}}\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, h](const char* data, size_t size, double)
|
||||
{
|
||||
ChainMain block;
|
||||
if (!parse_block_header(data, size, block)) {
|
||||
LOGERR(1, "couldn't download block header for height " << h);
|
||||
}
|
||||
},
|
||||
[h](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "couldn't download block header for height " << h << ", error " << log::const_buf(data, size));
|
||||
}
|
||||
});
|
||||
if (!m_missingHeights.empty()) {
|
||||
const int err = uv_async_send(&m_getMissingHeightsAsync);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_send failed, error " << uv_err_name(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void p2pool::get_missing_heights()
|
||||
{
|
||||
uint64_t h;
|
||||
{
|
||||
MutexLock lock(m_missingHeightsLock);
|
||||
|
||||
if (m_missingHeights.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
h = m_missingHeights.back();
|
||||
m_missingHeights.pop_back();
|
||||
}
|
||||
|
||||
LOGWARN(3, "Mainchain data for height " << h << " is missing, requesting it from monerod again");
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1] = {};
|
||||
log::Stream s(buf);
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << h << "}}\0";
|
||||
|
||||
const Params::Host& host = current_host();
|
||||
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
|
||||
[this, h](const char* data, size_t size, double)
|
||||
{
|
||||
ChainMain block;
|
||||
if (!parse_block_header(data, size, block)) {
|
||||
LOGERR(1, "couldn't download block header for height " << h);
|
||||
|
||||
MutexLock lock(m_missingHeightsLock);
|
||||
m_missingHeights.push_back(h);
|
||||
}
|
||||
get_missing_heights();
|
||||
},
|
||||
[this, h](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "couldn't download block header for height " << h << ", error " << log::const_buf(data, size));
|
||||
|
||||
MutexLock lock(m_missingHeightsLock);
|
||||
m_missingHeights.push_back(h);
|
||||
}
|
||||
get_missing_heights();
|
||||
});
|
||||
}
|
||||
|
||||
const char* BLOCK_FOUND = "\n\
|
||||
-----------------------------------------------------------------------------------------------\n\
|
||||
| ###### # ####### ##### # # ####### ####### # # # # ###### |\n\
|
||||
@@ -599,6 +643,10 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
|
||||
m_zmqLastActive = seconds_since_epoch();
|
||||
}
|
||||
|
||||
void p2pool::handle_monero_block_broadcast(std::vector<std::vector<uint8_t>>&& blobs)
|
||||
{
|
||||
m_p2pServer->broadcast_monero_block_async(std::move(blobs));
|
||||
}
|
||||
|
||||
#ifdef WITH_MERGE_MINING_DONATION
|
||||
void p2pool::set_aux_job_donation(const std::vector<IMergeMiningClient::ChainParameters>& chain_params)
|
||||
@@ -988,6 +1036,7 @@ void p2pool::on_stop(uv_async_t* async)
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_blockTemplateAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_stopAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_reconnectToHostAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_getMissingHeightsAsync), nullptr);
|
||||
|
||||
init_signals(pool, false);
|
||||
|
||||
@@ -1041,6 +1090,9 @@ void p2pool::submit_block() const
|
||||
const uint32_t nonce = submit_data.nonce;
|
||||
const uint32_t extra_nonce = submit_data.extra_nonce;
|
||||
|
||||
std::vector<uint8_t> blob;
|
||||
blob.reserve(submit_data.blob.size());
|
||||
|
||||
for (size_t i = 0; i < submit_data.blob.size(); ++i) {
|
||||
uint8_t b;
|
||||
if (nonce_offset && nonce_offset <= i && i < nonce_offset + sizeof(submit_data.nonce)) {
|
||||
@@ -1057,11 +1109,16 @@ void p2pool::submit_block() const
|
||||
else {
|
||||
b = submit_data.blob[i];
|
||||
}
|
||||
|
||||
request.append(1, "0123456789abcdef"[b >> 4]);
|
||||
request.append(1, "0123456789abcdef"[b & 15]);
|
||||
|
||||
blob.push_back(b);
|
||||
}
|
||||
request.append("\"]}");
|
||||
|
||||
m_p2pServer->store_monero_block_broadcast(blob.data(), static_cast<uint32_t>(blob.size()));
|
||||
|
||||
const Params::Host& host = current_host();
|
||||
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, request, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
|
||||
|
||||
@@ -86,6 +86,7 @@ public:
|
||||
virtual void handle_tx(TxMempoolData& tx) override;
|
||||
virtual void handle_miner_data(MinerData& data) override;
|
||||
virtual void handle_chain_main(ChainMain& data, const char* extra) override;
|
||||
virtual void handle_monero_block_broadcast(std::vector<std::vector<uint8_t>>&& blobs) override;
|
||||
|
||||
#ifdef WITH_MERGE_MINING_DONATION
|
||||
void set_aux_job_donation(const std::vector<IMergeMiningClient::ChainParameters>& chain_params);
|
||||
@@ -150,6 +151,7 @@ private:
|
||||
static void on_update_block_template(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->update_block_template(); }
|
||||
static void on_stop(uv_async_t*);
|
||||
static void on_reconnect_to_host(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->reconnect_to_host(); }
|
||||
static void on_get_missing_heights(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->get_missing_heights(); }
|
||||
|
||||
void submit_block() const;
|
||||
void submit_aux_block() const;
|
||||
@@ -260,6 +262,13 @@ private:
|
||||
uint64_t m_startTime;
|
||||
uv_async_t m_reconnectToHostAsync;
|
||||
|
||||
uv_async_t m_getMissingHeightsAsync;
|
||||
|
||||
mutable uv_mutex_t m_missingHeightsLock;
|
||||
mutable std::vector<uint64_t> m_missingHeights;
|
||||
|
||||
void get_missing_heights();
|
||||
|
||||
#ifndef P2POOL_UNIT_TESTS
|
||||
mutable uv_rwlock_t m_ZMQReaderLock;
|
||||
ZMQReader* m_ZMQReader = nullptr;
|
||||
|
||||
@@ -258,6 +258,11 @@ Params::Params(int argc, char* const argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcmp(argv[i], "--full-validation") == 0) {
|
||||
m_enableFullValidation = true;
|
||||
ok = true;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -116,6 +116,7 @@ struct Params
|
||||
uint8_t priv_key[64];
|
||||
};
|
||||
#endif
|
||||
bool m_enableFullValidation = false;
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+1
-6
@@ -343,13 +343,8 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
|
||||
|
||||
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;
|
||||
memcpy(hashes + HASH_SIZE, keccak_0x00.h, HASH_SIZE);
|
||||
|
||||
// Third hash is null because there is no rct data in the coinbase transaction
|
||||
memset(hashes + HASH_SIZE * 2, 0, HASH_SIZE);
|
||||
|
||||
+28
-22
@@ -47,6 +47,7 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
: TCPServer(DEFAULT_BACKLOG, StratumClient::allocate, std::string())
|
||||
, m_pool(pool)
|
||||
, m_autoDiff(pool->params().m_autoDiff)
|
||||
, m_enableFullValidation(pool->params().m_enableFullValidation)
|
||||
, m_rng(RandomDeviceSeed::instance)
|
||||
, m_cumulativeHashes(0)
|
||||
, m_cumulativeHashesAtLastShare(0)
|
||||
@@ -480,7 +481,7 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
update_auto_diff(client, share.m_timestamp, share.m_hashes);
|
||||
|
||||
// If this share is below sidechain difficulty, process it in this thread because it'll be quick
|
||||
if (!share.m_highEnoughDifficulty) {
|
||||
if (!share.m_highEnoughDifficulty && !m_enableFullValidation) {
|
||||
on_share_found(&share.m_req);
|
||||
on_after_share_found(&share.m_req, 0);
|
||||
return true;
|
||||
@@ -951,7 +952,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
return;
|
||||
}
|
||||
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
if (share->m_highEnoughDifficulty || server->m_enableFullValidation) {
|
||||
BACKGROUND_JOB_START(StratumServer::on_share_found);
|
||||
}
|
||||
|
||||
@@ -960,7 +961,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
const uint64_t target = share->m_target;
|
||||
const uint64_t hashes = share->m_hashes;
|
||||
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
if (share->m_highEnoughDifficulty || server->m_enableFullValidation) {
|
||||
if (pool->stopped()) {
|
||||
LOGWARN(0, "p2pool is shutting down, but a share was found. Trying to process it anyway!");
|
||||
}
|
||||
@@ -1008,30 +1009,32 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
|
||||
share->m_score = GOOD_SHARE_POINTS;
|
||||
|
||||
const double diff = sidechain_difficulty.to_double();
|
||||
time_t prev_time;
|
||||
const time_t cur_time = time(nullptr);
|
||||
{
|
||||
WriteLock lock(server->m_hashrateDataLock);
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
const double diff = sidechain_difficulty.to_double();
|
||||
time_t prev_time;
|
||||
const time_t cur_time = time(nullptr);
|
||||
{
|
||||
WriteLock lock(server->m_hashrateDataLock);
|
||||
|
||||
const uint64_t n = server->m_cumulativeHashes + hashes;
|
||||
share->m_effort = static_cast<double>(n - server->m_cumulativeHashesAtLastShare) * 100.0 / diff;
|
||||
server->m_cumulativeHashesAtLastShare = n;
|
||||
const uint64_t n = server->m_cumulativeHashes + hashes;
|
||||
share->m_effort = static_cast<double>(n - server->m_cumulativeHashesAtLastShare) * 100.0 / diff;
|
||||
server->m_cumulativeHashesAtLastShare = n;
|
||||
|
||||
server->m_cumulativeFoundSharesDiff += diff;
|
||||
++server->m_totalFoundSidechainShares;
|
||||
server->m_cumulativeFoundSharesDiff += diff;
|
||||
++server->m_totalFoundSidechainShares;
|
||||
|
||||
prev_time = server->m_lastSidechainShareFoundTime;
|
||||
server->m_lastSidechainShareFoundTime = cur_time;
|
||||
}
|
||||
prev_time = server->m_lastSidechainShareFoundTime;
|
||||
server->m_lastSidechainShareFoundTime = cur_time;
|
||||
}
|
||||
|
||||
if (!pool->submit_sidechain_block(share->m_templateId, share->m_nonce, share->m_extraNonce)) {
|
||||
WriteLock lock(server->m_hashrateDataLock);
|
||||
if (!pool->submit_sidechain_block(share->m_templateId, share->m_nonce, share->m_extraNonce)) {
|
||||
WriteLock lock(server->m_hashrateDataLock);
|
||||
|
||||
if (server->m_totalFoundSidechainShares > 0) {
|
||||
--server->m_totalFoundSidechainShares;
|
||||
++server->m_totalFailedSidechainShares;
|
||||
server->m_lastSidechainShareFoundTime = prev_time;
|
||||
if (server->m_totalFoundSidechainShares > 0) {
|
||||
--server->m_totalFoundSidechainShares;
|
||||
++server->m_totalFailedSidechainShares;
|
||||
server->m_lastSidechainShareFoundTime = prev_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1078,6 +1081,9 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
const char* reason = (k < array_size(reason_list)) ? reason_list[k] : "unknown";
|
||||
LOGWARN(0, "INVALID SHARE: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(share->m_clientAddrString) << (*s ? ", user " : "") << s << ", reason: " << reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (share->m_highEnoughDifficulty || server->m_enableFullValidation) {
|
||||
BACKGROUND_JOB_STOP(StratumServer::on_share_found);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
|
||||
p2pool* m_pool;
|
||||
bool m_autoDiff;
|
||||
|
||||
bool m_enableFullValidation;
|
||||
struct BlobsData
|
||||
{
|
||||
uint32_t m_extraNonceStart;
|
||||
|
||||
+2
-1
@@ -35,7 +35,7 @@
|
||||
namespace p2pool {
|
||||
|
||||
#define P2POOL_VERSION_MAJOR 4
|
||||
#define P2POOL_VERSION_MINOR 9
|
||||
#define P2POOL_VERSION_MINOR 10
|
||||
#define P2POOL_VERSION_PATCH 1
|
||||
|
||||
constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;
|
||||
@@ -92,6 +92,7 @@ struct MinerCallbackHandler
|
||||
virtual void handle_tx(TxMempoolData& tx) = 0;
|
||||
virtual void handle_miner_data(MinerData& data) = 0;
|
||||
virtual void handle_chain_main(ChainMain& data, const char* extra) = 0;
|
||||
virtual void handle_monero_block_broadcast(std::vector<std::vector<uint8_t>>&& blobs) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
+181
-2
@@ -253,6 +253,177 @@ bool ZMQReader::connect(const std::string& address, bool keep_monitor)
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> construct_monero_block_blob(rapidjson::Value* value)
|
||||
{
|
||||
std::vector<uint8_t> empty_blob;
|
||||
|
||||
#define X(type, name) type name; if (!parseValue(*value, #name, name)) return empty_blob;
|
||||
|
||||
X(uint8_t, major_version);
|
||||
X(uint8_t, minor_version);
|
||||
X(uint64_t, timestamp);
|
||||
X(std::string, prev_id);
|
||||
X(uint32_t, nonce);
|
||||
|
||||
#undef X
|
||||
|
||||
auto miner_tx = value->FindMember("miner_tx");
|
||||
|
||||
if ((miner_tx == value->MemberEnd()) || !miner_tx->value.IsObject()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: miner_tx not found or is not an object");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
if (!parseValue(miner_tx->value, "version", version)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: version not found");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
uint64_t unlock_height;
|
||||
if (!parseValue(miner_tx->value, "unlock_time", unlock_height)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: unlock_time not found");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
std::string extra;
|
||||
if (!parseValue(miner_tx->value, "extra", extra)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: extra not found");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
auto outputs = miner_tx->value.FindMember("outputs");
|
||||
|
||||
if ((outputs == miner_tx->value.MemberEnd()) || !outputs->value.IsArray()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: outputs not found or is not an array");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
auto tx_hashes = value->FindMember("tx_hashes");
|
||||
|
||||
if ((tx_hashes == value->MemberEnd()) || !tx_hashes->value.IsArray()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: tx_hashes not found or is not an array");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> blob;
|
||||
blob.reserve(16384);
|
||||
|
||||
blob.push_back(major_version);
|
||||
blob.push_back(minor_version);
|
||||
|
||||
writeVarint(timestamp, blob);
|
||||
|
||||
hash h;
|
||||
if (!from_hex(prev_id.c_str(), prev_id.length(), h)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: invalid prev_id " << prev_id);
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
blob.insert(blob.end(), h.h, h.h + HASH_SIZE);
|
||||
blob.insert(blob.end(), reinterpret_cast<const uint8_t*>(&nonce), reinterpret_cast<const uint8_t*>(&nonce) + NONCE_SIZE);
|
||||
|
||||
MoneroBlockBroadcastHeader data;
|
||||
|
||||
data.header_size = static_cast<uint32_t>(blob.size());
|
||||
|
||||
blob.insert(blob.end(), version);
|
||||
|
||||
writeVarint(unlock_height, blob);
|
||||
|
||||
blob.push_back(1);
|
||||
blob.push_back(TXIN_GEN);
|
||||
|
||||
writeVarint(unlock_height - MINER_REWARD_UNLOCK_TIME, blob);
|
||||
|
||||
auto arr = outputs->value.GetArray();
|
||||
|
||||
if (arr.Empty()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: outputs array is empty");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
writeVarint(arr.Size(), blob);
|
||||
|
||||
for (auto i = arr.begin(); i != arr.end(); ++i) {
|
||||
auto amount = i->FindMember("amount");
|
||||
if ((amount == i->MemberEnd()) || !amount->value.IsUint64()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: amount not found or is not UInt64");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
auto to_tagged_key = i->FindMember("to_tagged_key");
|
||||
if ((to_tagged_key == i->MemberEnd()) || !to_tagged_key->value.IsObject()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: to_tagged_key not found or is not an object");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
auto key = to_tagged_key->value.FindMember("key");
|
||||
if ((key == to_tagged_key->value.MemberEnd()) || !key->value.IsString()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: key not found or is not a string");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
auto view_tag = to_tagged_key->value.FindMember("view_tag");
|
||||
if ((view_tag == to_tagged_key->value.MemberEnd()) || !view_tag->value.IsString()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: view_tag not found or is not a string");
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
writeVarint(amount->value.GetUint64(), blob);
|
||||
blob.push_back(TXOUT_TO_TAGGED_KEY);
|
||||
|
||||
if (!from_hex(key->value.GetString(), key->value.GetStringLength(), h)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: invalid key " << key->value.GetString());
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
blob.insert(blob.end(), h.h, h.h + HASH_SIZE);
|
||||
|
||||
std::vector<uint8_t> t;
|
||||
if (!from_hex(view_tag->value.GetString(), view_tag->value.GetStringLength(), t) || (t.size() != 1)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: invalid view_tag " << view_tag->value.GetString());
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
blob.push_back(t[0]);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> t;
|
||||
if (!from_hex(extra.c_str(), extra.length(), t) || (t.size() < HASH_SIZE + 1)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: invalid extra " << extra);
|
||||
return empty_blob;
|
||||
}
|
||||
|
||||
writeVarint(t.size(), blob);
|
||||
blob.insert(blob.end(), t.begin(), t.end());
|
||||
|
||||
blob.push_back(0);
|
||||
|
||||
data.miner_tx_size = static_cast<uint32_t>(blob.size()) - data.header_size;
|
||||
|
||||
auto arr2 = tx_hashes->value.GetArray();
|
||||
|
||||
writeVarint(arr2.Size(), blob);
|
||||
|
||||
for (auto i = arr2.begin(); i != arr2.end(); ++i) {
|
||||
if (!i->IsString()) {
|
||||
LOGWARN(3, "construct_monero_block_blob: tx_hash is not a string");
|
||||
return empty_blob;
|
||||
}
|
||||
if (!from_hex(i->GetString(), i->GetStringLength(), h)) {
|
||||
LOGWARN(3, "construct_monero_block_blob: invalid tx_hash " << i->GetString());
|
||||
return empty_blob;
|
||||
}
|
||||
blob.insert(blob.end(), h.h, h.h + HASH_SIZE);
|
||||
}
|
||||
|
||||
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data);
|
||||
blob.insert(blob.begin(), p, p + sizeof(data));
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
void ZMQReader::parse(char* data, size_t size)
|
||||
{
|
||||
char* value = data;
|
||||
@@ -344,12 +515,18 @@ void ZMQReader::parse(char* data, size_t size)
|
||||
}
|
||||
else if (strcmp(data, "json-full-chain_main") == 0) {
|
||||
if (!doc.IsArray()) {
|
||||
LOGWARN(1, "json-full-chain_main is not an object, skipping it");
|
||||
LOGWARN(1, "json-full-chain_main is not an array, skipping it");
|
||||
return;
|
||||
}
|
||||
|
||||
auto arr = doc.GetArray();
|
||||
for (Value* i = arr.begin(); i != arr.end(); ++i) {
|
||||
|
||||
std::vector<std::vector<uint8_t>> blobs;
|
||||
blobs.reserve(arr.Size());
|
||||
|
||||
for (auto i = arr.begin(); i != arr.end(); ++i) {
|
||||
blobs.emplace_back(construct_monero_block_blob(i));
|
||||
|
||||
if (!PARSE(*i, m_chainmainData, timestamp)) {
|
||||
LOGWARN(1, "json-full-chain_main timestamp failed to parse, skipping it");
|
||||
continue;
|
||||
@@ -411,6 +588,8 @@ void ZMQReader::parse(char* data, size_t size)
|
||||
|
||||
m_handler->handle_chain_main(m_chainmainData, extra_it->value.GetString());
|
||||
}
|
||||
|
||||
m_handler->handle_monero_block_broadcast(std::move(blobs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user