Compare commits

...

34 Commits

Author SHA1 Message Date
SChernykh 42370bf11e p2pool v1.7 2022-02-14 19:29:55 +01:00
SChernykh dc506bb1b9 Update README.md 2022-02-14 14:08:36 +01:00
SChernykh ec2f4467fb Added --mini command line option to connect to p2pool-mini 2022-02-14 13:57:59 +01:00
SChernykh 9f449320b5 StartumServer: disconnect and ban inactive clients 2022-02-08 15:00:08 +01:00
SChernykh 8767ef9e19 Display payout amount when a block is found 2022-01-29 17:09:43 +01:00
SChernykh cf184295b4 Updated version 2022-01-26 19:42:49 +01:00
SChernykh 0cd9876a46 Updated dependencies 2022-01-25 00:05:38 +01:00
SChernykh 1e4e4bd08e Added miner statistics to data api 2022-01-24 10:42:21 +01:00
SChernykh a640e41d74 Improved RNG initialization 2022-01-24 00:37:39 +01:00
SChernykh f90e00edea Moved "how to mine" up in the readme 2022-01-23 15:55:57 +01:00
SChernykh 38ffd73b54 Fixed new Coverity issue 2022-01-23 13:03:56 +01:00
SChernykh c10a5ce323 Miner code cleanup 2022-01-23 11:03:26 +01:00
SChernykh e2931f94b5 Added embedded miner 2022-01-22 23:30:19 +01:00
SChernykh 95c268be4c Update msvc-analysis.yml 2022-01-20 13:41:38 +01:00
SChernykh 4ac4f8f860 Update README.md
XMR block reward has decreased, so minimum payout is now ~0.0003 XMR
2022-01-20 13:22:34 +01:00
SChernykh 248fcee174 Update version 2022-01-09 17:19:20 +01:00
SChernykh 89bcceb986 Added p2pool mini seed nodes and default port 2021-12-30 11:10:18 +01:00
SChernykh 2b01350add Added outpeers and inpeers console commands 2021-12-26 15:28:33 +01:00
SChernykh f1b6212c82 P2PServer: add connection limits
#87 Added `--out-peers` and `--in-peers` command line options.
2021-12-26 14:59:45 +01:00
SChernykh 7d961ab3b9 Merge pull request #89 from bladedoyle/monero_p2pool_support
Monero latest release supports p2pool
2021-12-24 22:40:54 +01:00
Blade Doyle 862e7d965b Monero latest release supports p2pool 2021-12-24 11:38:53 -08:00
SChernykh da2d9f7e2e Update README.md 2021-12-07 19:11:51 +01:00
SChernykh d8bba4dc82 Updated version mismatch error message 2021-12-07 16:25:23 +01:00
SChernykh 3a8a24a5ee Updated dependencies 2021-12-07 16:09:21 +01:00
SChernykh eaf29872cb Update version 2021-12-01 18:24:36 +01:00
SChernykh 74f553274f Update c-cpp.yml
Use macos-10.15 instead of "latest".
2021-11-23 14:08:38 +01:00
SChernykh d0f1e6eb2e Merge pull request #78 from SChernykh/calcpow
Added "calc_pow" RPC support
2021-11-21 09:20:01 +01:00
SChernykh f9def6cb73 Added "calc_pow" RPC support 2021-11-21 09:12:21 +01:00
SChernykh 2f659c8ecf Update c-cpp.yml 2021-11-11 22:59:04 +01:00
SChernykh 2d559ca764 Merge pull request #71 from bladedoyle/docker-compose
docker-compose project for Monero P2Pool and all requirements
2021-11-11 22:00:29 +01:00
Blade Doyle 1328ea6aef docker-compose project for Monero P2Pool and all requirements 2021-11-11 12:52:03 -08:00
SChernykh 07cfb54bdc JSONRPCRequest: fixed undefined behavior in the error handler 2021-11-10 16:26:01 +01:00
SChernykh 5dd8d11b72 TCPServer: removed unused field 2021-11-09 15:48:59 +01:00
SChernykh dbab191bfc C/C++ CI: use GCC 11 for the ubuntu-latest build 2021-11-08 16:03:43 +01:00
50 changed files with 1222 additions and 228 deletions
+13 -8
View File
@@ -9,15 +9,20 @@ on:
jobs:
build-ubuntu:
runs-on: ${{ matrix.os }}
runs-on: ${{ matrix.config.os }}
strategy:
matrix:
os: [ubuntu-latest, ubuntu-18.04]
config:
- {os: ubuntu-latest, c: gcc-11, cpp: g++-11}
- {os: ubuntu-18.04, c: gcc, cpp: g++}
steps:
- name: Install dependencies
run: sudo apt update && sudo apt install git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev
run: |
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev ${{ matrix.config.c }} ${{ matrix.config.cpp }}
- name: Checkout repository
uses: actions/checkout@v2
@@ -28,7 +33,7 @@ jobs:
run: |
mkdir build
cd build
cmake ..
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }}
make -j2
- name: Build tests
@@ -36,7 +41,7 @@ jobs:
cd tests
mkdir build
cd build
cmake ..
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }}
make -j2
- name: Run tests
@@ -45,7 +50,7 @@ jobs:
- name: Archive binary
uses: actions/upload-artifact@v2
with:
name: p2pool-${{ matrix.os }}
name: p2pool-${{ matrix.config.os }}
path: build/p2pool
build-windows-msys2:
@@ -102,7 +107,7 @@ jobs:
matrix:
config:
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\"}
- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Preview\\Msbuild\\Current\\Bin\\amd64\\"}
- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\"}
steps:
- name: Checkout repository
@@ -145,7 +150,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, macos-11]
os: [macos-10.15, macos-11]
steps:
- name: Checkout repository
+4 -2
View File
@@ -19,6 +19,7 @@ on:
env:
# Path to the CMake build directory.
build: '${{ github.workspace }}/build'
config: 'Release'
jobs:
analyze:
@@ -32,18 +33,19 @@ jobs:
submodules: true
- name: Configure CMake
run: cmake -B ${{ env.build }}
run: cmake -B ${{ env.build }} -DCMAKE_BUILD_TYPE=${{ env.config }}
# Build is not required unless generated source files are used
# - name: Build CMake
# run: cmake --build ${{ env.build }}
- name: Initialize MSVC Code Analysis
uses: microsoft/msvc-code-analysis-action@04825f6d9e00f87422d6bf04e1a38b1f3ed60d99
uses: microsoft/msvc-code-analysis-action@47ecec99bf7ce0399ed85cbb5012b6f24eab5959
# Provide a unique ID to access the sarif output path
id: run-analysis
with:
cmakeBuildDirectory: ${{ env.build }}
buildConfiguration: ${{ env.config }}
# Ruleset file that will determine what checks will be run
ruleset: NativeRecommendedRules.ruleset
+2
View File
@@ -27,6 +27,7 @@ set(HEADERS
src/keccak.h
src/log.h
src/mempool.h
src/miner.h
src/p2p_server.h
src/p2pool.h
src/p2pool_api.h
@@ -60,6 +61,7 @@ set(SOURCES
src/main.cpp
src/memory_leak_debug.cpp
src/mempool.cpp
src/miner.cpp
src/p2p_server.cpp
src/p2pool.cpp
src/p2pool_api.cpp
+50
View File
@@ -0,0 +1,50 @@
FROM ubuntu:latest
RUN set -e && \
apt-get update -q -y --no-install-recommends && \
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
git \
build-essential \
ca-certificates \
cmake \
libuv1-dev \
libzmq3-dev \
libsodium-dev \
libpgm-dev \
libnorm-dev \
libgss-dev
ADD . /usr/src/p2pool
WORKDIR /usr/src/p2pool
RUN git submodule update --init --recursive && \
mkdir build && \
cd build && \
cmake .. && \
make -j$(nproc)
# ---
FROM ubuntu:latest
COPY --from=0 /usr/src/p2pool/build/p2pool /
RUN set -e && \
apt-get update -q -y --no-install-recommends && \
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
libzmq5 \
libuv1 \
&& \
apt-get clean
RUN groupadd -r p2pool -g 1000 && \
useradd -u 1000 -r -g p2pool -s /sbin/nologin -c "p2pool user" p2pool
RUN mkdir -p /home/p2pool/.p2pool && \
chown p2pool.p2pool /home/p2pool /home/p2pool/.p2pool
USER p2pool
EXPOSE 3333
EXPOSE 37889
VOLUME /home/p2pool/.p2pool
WORKDIR /home/p2pool/.p2pool
ENTRYPOINT ["/p2pool"]
+83 -110
View File
@@ -8,6 +8,7 @@ Pool status and monitoring pages can be found at https://p2pool.io/ and https://
![C/C++ CI](https://github.com/SChernykh/p2pool/actions/workflows/c-cpp.yml/badge.svg)
![CodeQL](https://github.com/SChernykh/p2pool/actions/workflows/codeql-analysis.yml/badge.svg)
![msvc-analysis](https://github.com/SChernykh/p2pool/actions/workflows/msvc-analysis.yml/badge.svg)
![cppcheck](https://github.com/SChernykh/p2pool/actions/workflows/cppcheck.yml/badge.svg)
<a href="https://scan.coverity.com/projects/schernykh-p2pool">
<img alt="Coverity Scan Build Status"
@@ -22,7 +23,7 @@ Here's the comparison table of the different ways of mining. While pool mining i
|-|-|-|-|-|-|-|-|
|Centralized pool|Regular|0-3%|0.001-0.01 XMR|Yes|Less stable due to pool server outages|Pool admin controls your mined funds, what you mine and can execute network attacks|Only miner software is required
|Solo|Rare|0%|0.6 XMR or more|No|As stable as your Monero node|100% under your control|Monero node + optional miner
|**P2Pool**|Regular|0%|less than 0.0004 XMR|No|As stable as your Monero node|100% under your control|Monero node + P2Pool node + miner
|**P2Pool**|Regular|0%|~0.0003 XMR|No|As stable as your Monero node|100% under your control|Monero node + P2Pool node + miner
## Features
@@ -32,7 +33,7 @@ Here's the comparison table of the different ways of mining. While pool mining i
* PPLNS payout scheme
* **0% fee**
* **0 XMR payout fee**
* **Less than 0.0004 XMR minimal payout**
* **~0.0003 XMR minimal payout**
* Fast block times, down to 1 second
* Uncle blocks are supported to avoid orphans - all your shares will be accounted for!
* Configurable PPLNS window size and block time
@@ -49,7 +50,86 @@ First you need to find a pool share. This share will stay in PPLNS window for 21
* Block time: 10 seconds
* PPLNS window: 2160 blocks (6 hours)
* Minimum payout = Monero block reward/2160, currently ~0.0004 XMR
* Minimum payout = Monero block reward/2160, ~0.0003 XMR
## How to mine on P2Pool
This guide assumes that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup. It's highly recommended to create a new mainnet wallet for mining because **wallet addresses are public on p2pool**.
**Wallet software compatible with p2pool payouts**
- Official Monero CLI and GUI v0.17.2.3 and newer
- Monerujo v2.1.0 "Vertant" and newer
- Cake Wallet v4.2.7 and newer
- Feather Wallet v1.0.0 and newer
- MyMonero
**General Considerations**
- Create a separate restricted user account for mining. p2pool is relatively new and may still have serious bugs/vulnerabilities!
- You have to use the primary wallet address for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
- Check that ports 18080 (Monero p2p port) and 37889 (p2pool p2p port) are open in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine.
- You can connect multiple miners to the same p2pool node. The more the better!
- Starting from p2pool v1.7, you can add `--mini` to p2pool command line to connect to the **p2pool-mini** sidechain. Note that it will also change the default p2p port from 37889 to 37888.
Step-by-step guide:
### GNU/Linux
- Download binaries from https://github.com/SChernykh/p2pool/releases/latest
- Alternatively, grab the latest source code for p2pool and build it
- Prepare enough huge pages (each of monerod/p2pool/xmrig needs them): `sudo sysctl vm.nr_hugepages=3072`
- Get xmrig (linux-static-x64) binary from https://github.com/xmrig/xmrig/releases/latest
- Check that ports 18080 (Monero p2p port) and 37889 (p2pool p2p port) are open in your firewall to ensure better connectivity
- Use the `monerod` binary v0.17.3.0 or newer
- Run `./monerod --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist` **don't forget --zmq-pub parameter in the command line**
- Run `./p2pool --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS`
- p2pool has verbose logging by default, you can reduce it by using "loglevel N" command where N is between 0 and 6. Default loglevel is 3.
- You can use `logrotate` with a config like this to control logfile growth:
```
<path-to-logfile>
{
rotate 7
daily
missingok
delaycompress
nocreate
}
```
- Wait until initial p2pool sync is finished, it shouldn't take more than 5-10 minutes, once completed xmrig should be able to connect to the stratum server on port 3333.
- Run `./xmrig -o 127.0.0.1:3333`. Note that you don't need to specify wallet address for xmrig. **Wallet address set in xmrig config will be ignored!**
- To set custom fixed difficulty for your miner (for example, 10000), run `./xmrig -u x+10000 -o 127.0.0.1:3333`
- xmrig should connect and start mining
- Also check p2pool.log for any warnings and errors: `grep -E 'WARNING|ERROR' p2pool.log`
### Windows
*NOTE: Windows SmartScreen may block incoming connections by files that are "Downloaded from the Internet". You can allow 'p2pool.exe' and 'monerod.exe' by double-clicking them, clicking "More Info", then click "Run Anyway" and then closing them immediately so you can run them from the command line. Advanced users can use the PowerShell cmdlet `Unblock-File` to remove this flag.*
- Download p2pool binaries from https://github.com/SChernykh/p2pool/releases/latest
- Download xmrig binary from https://github.com/xmrig/xmrig/releases/latest *(xmrig-6.15.2-gcc-win64.zip is the current version)*
- Expand the p2pool binaries into an appropriate location (`%USERPROFILE%/bin` or `C:/bin/` are good options)
- Expand xmrig binary into appropriate location (same folder as p2pool is fine)
- Prepare huge pages (each of monerod/p2pool/xmrig needs them):
- On Windows 10 or above, run xmrig at least once as Administrator (right-click Run As Administrator)
- On earlier versions of Windows, you'll need to run it as admin at least once per login.
- Open a command prompt and navigate to the folder where you extracted p2pool.
- *When running these commands, Windows Firewall may prompt to allow connections, click "Allow"*
- Run `.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist` *NOTE: don't forget --zmq-pub parameter in the command line*
- Run `.\p2pool.exe --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS`
- Wait until initial p2pool sync is finished, it shouldn't take more than 5-10 minutes, once completed xmrig should be able to connect to the stratum server on port 3333.
- Run `.\xmrig.exe -o 127.0.0.1:3333`. Note that you don't need to specify wallet address for xmrig. **Wallet address set in xmrig config will be ignored!**
- To set custom fixed difficulty for your miner (for example, 10000), run `xmrig.exe -u x+10000 -o 127.0.0.1:3333`
- Windows Quickstart: Create a batch (.bat) file with the following contents and place 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 --disable-dns-checkpoints --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
ECHO Wait until the daemon shows fully synced before continuing. This can take some time.
PAUSE
%~dp0\xmrig.exe -u x+30000 -o 127.0.0.1
```
## Build instructions
@@ -65,16 +145,6 @@ cmake ..
make -j$(nproc)
```
monerod binary compatible with p2pool:
```
sudo apt update && sudo apt install git build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev libpgm-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 ccache doxygen graphviz
git clone --recursive https://github.com/monero-project/monero/
cd monero
git checkout release-v0.17
git submodule sync && git submodule update --init --force --recursive
make release-static -j$(nproc)
```
### Arch Linux [AUR](https://wiki.archlinux.org/title/Arch_User_Repository)
Make the package: [p2pool-git](https://aur.archlinux.org/packages/p2pool-git/)
@@ -111,16 +181,6 @@ cmake ..
make -j$(sysctl -n hw.logicalcpu)
```
monerod binary compatible with p2pool:
```
git clone --recursive https://github.com/monero-project/monero/
cd monero
git checkout release-v0.17
git submodule sync && git submodule update --init --force --recursive
brew update && brew bundle --file=contrib/brew/Brewfile
make -j$(sysctl -n hw.logicalcpu)
```
### Windows
p2pool binary (Visual Studio Community 2019 build):
@@ -136,93 +196,6 @@ then open generated build\p2pool.sln in Visual Studio and build it there
Alternatively, you can select "Clone a repository" within the GUI, then select "Build" from the menu.
monerod binary compatible with p2pool:
```
git clone --recursive https://github.com/monero-project/monero/
cd monero
git checkout release-v0.17
git submodule sync && git submodule update --init --force --recursive
```
then follow the instructions from https://github.com/monero-project/monero/#on-windows
## How to mine on P2Pool
This guide assumes that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup. It's highly recommended to create a new mainnet wallet for mining because **wallet addresses are public on p2pool**.
**Wallet software compatible with p2pool payouts**
- Official Monero CLI and GUI v0.17.2.3 and newer
- Monerujo v2.1.0 "Vertant" and newer
- Cake Wallet v4.2.7 and newer
- MyMonero
**General Considerations**
- Create a separate restricted user account for mining. p2pool is relatively new and may still have serious bugs/vulnerabilities!
- You have to use the primary wallet address for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
- Check that ports 18080 (Monero p2p port) and 37889 (p2pool p2p port) are open in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine.
- You can connect multiple miners to the same p2pool node. The more the better!
Step-by-step guide:
### GNU/Linux
- Download binaries from https://github.com/SChernykh/p2pool/releases/latest
- Alternatively, grab the latest source code for both p2pool and monerod and build them (see above, also notice that the branch name for monerod changed, you'll need to checkout p2pool-api-v0.17)
- Prepare enough huge pages (each of monerod/p2pool/xmrig needs them): `sudo sysctl vm.nr_hugepages=3072`
- Get xmrig (linux-static-x64) binary from https://github.com/xmrig/xmrig/releases/latest
- Check that ports 18080 (Monero p2p port) and 37889 (p2pool p2p port) are open in your firewall to ensure better connectivity
- Use the `monerod` binary bundled with p2pool (official binaries don't have p2pool support yet)
- Run `./monerod --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist` **don't forget --zmq-pub parameter in the command line**
- Double check that it shows **Monero 'Oxygen Orion' (v0.17.2.3-fce167d7c)** on startup. Wait until it's synchronized.
- Run `./p2pool --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS`
- p2pool has verbose logging by default, you can reduce it by using "loglevel N" command where N is between 0 and 6. Default loglevel is 3.
- You can use `logrotate` with a config like this to control logfile growth:
```
<path-to-logfile>
{
rotate 7
daily
missingok
delaycompress
nocreate
}
```
- Wait until initial p2pool sync is finished, it shouldn't take more than 5-10 minutes, once completed xmrig should be able to connect to the stratum server on port 3333.
- Run `./xmrig -o 127.0.0.1:3333`. Note that you don't need to specify wallet address for xmrig. **Wallet address set in xmrig config will be ignored!**
- To set custom fixed difficulty for your miner (for example, 10000), run `./xmrig -u x+10000 -o 127.0.0.1:3333`
- xmrig should connect and start mining
- Also check p2pool.log for any warnings and errors: `grep -E 'WARNING|ERROR' p2pool.log`
### Windows
*NOTE: Windows SmartScreen may block incoming connections by files that are "Downloaded from the Internet". You can allow 'p2pool.exe' and 'monerod.exe' by double-clicking them, clicking "More Info", then click "Run Anyway" and then closing them immediately so you can run them from the command line. Advanced users can use the PowerShell cmdlet `Unblock-File` to remove this flag.*
- Download p2pool binaries from https://github.com/SChernykh/p2pool/releases/latest
- Download xmrig binary from https://github.com/xmrig/xmrig/releases/latest *(xmrig-6.15.2-gcc-win64.zip is the current version)*
- Expand the p2pool binaries into an appropriate location (`%USERPROFILE%/bin` or `C:/bin/` are good options)
- Expand xmrig binary into appropriate location (same folder as p2pool is fine)
- Prepare huge pages (each of monerod/p2pool/xmrig needs them):
- On Windows 10 or above, run xmrig at least once as Administrator (right-click Run As Administrator)
- On earlier versions of Windows, you'll need to run it as admin at least once per login.
- Open a command prompt and navigate to the folder where you extracted p2pool.
- *When running these commands, Windows Firewall may prompt to allow connections, click "Allow"*
- Run `.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --disable-dns-checkpoints --enable-dns-blocklist` *NOTE: don't forget --zmq-pub parameter in the command line*
- Double check that it shows **Monero 'Oxygen Orion' (v0.17.2.3-fce167d7c)** on startup. Wait until it's synchronized.
- Run `.\p2pool.exe --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS`
- Wait until initial p2pool sync is finished, it shouldn't take more than 5-10 minutes, once completed xmrig should be able to connect to the stratum server on port 3333.
- Run `.\xmrig.exe -o 127.0.0.1:3333`. Note that you don't need to specify wallet address for xmrig. **Wallet address set in xmrig config will be ignored!**
- To set custom fixed difficulty for your miner (for example, 10000), run `xmrig.exe -u x+10000 -o 127.0.0.1:3333`
- Windows Quickstart: Create a batch (.bat) file with the following contents and place 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 --disable-dns-checkpoints --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
ECHO Wait until the daemon shows fully synced before continuing. This can take some time.
PAUSE
%~dp0\xmrig.exe -u x+30000 -o 127.0.0.1
```
## Donations
+38
View File
@@ -0,0 +1,38 @@
##
# Monero Wallet Address for mining rewards (replace this with your own address)
WALLET_ADDRESS="44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg"
##
# p2pool settings
#
# Which port to listen for miner connections
P2POOL_STRATUM_PORT=3333
#
# How much logging - (Less) 0 - 6 (More)
P2POOL_LOGLEVEL=2
#
# The name of docker volume to hold p2pool data (created automatically if it doesnt exist)
P2POOL_VOLUME=p2pool
##
# Monero Node Settings
#
# Version of Monero to build. Must be v0.17.3.0 or later for p2pool support. "latest" pulls the most recent release tag
MONERO_GIT_TAG=latest
#
# Limit the size of the blockchain on disk (comment to disable)
PRUNE_NODE="--prune-blockchain"
#
# The name of docker volume to hold p2pool data (created automatically if it doesnt exist)
MONERO_VOLUME=monero
##
# Xmrig Miner Settings
#
# Submit shares at a lower fixed difficulty to show mining progress (comment to disable, edit to customize)
FIXED_MINING_DIFFICULTY="-u x+500000"
#
# Limit the number of CPU cores to use for mining (uncomment to enable, edit to customize)
#NUM_MINING_CPU="-t 4"
+49
View File
@@ -0,0 +1,49 @@
# Monero P2Pool Docker Compose
Run your own <b>Monero Node + P2Pool + XMRig</b> in Docker
## Instructions
#### Install docker and docker-compose
[Install Docker](https://docs.docker.com/engine/install/)
[Install Docker Compose](https://docs.docker.com/compose/install/)
#### Clone the P2Pool project
```
git clone --recursive https://github.com/SChernykh/p2pool
```
#### Configure your Monero address for mining rewards
```
cd p2pool/docker-compose
vi .env
```
**WALLET_ADDRESS** is the only setting that needs to be updated in that file
#### Build the docker containers
```
docker-compose build
```
#### Run the node, pool, and CPU miner
```
docker-compose up
```
#### Optional
* Open ports 18080 (Monero p2p port) and 37889 (P2Pool p2p port) in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine
* An XMRig CPU miner is included by default, but you can connect additional miners to this same p2pool node using port 3333
* Configure your kernel for maximum mining performance: [XMRig RandomX Optimization Guide](https://xmrig.com/docs/miner/randomx-optimization-guide)
#### Other usefull commands
* You can **run everythng in the background** by adding the "-d" argument to the "docker-compose up" command: ```docker-compose up -d```
* You can **stop everything** with CTRL-C or ```docker-compose down```
* You can see logs when running in the background for with the "docker logs" command: ```docker logs -f p2pool-xmrig``` or ```docker logs -f p2pool-p2pool``` or ```docker logs -f p2pool-monero```
#### Uninstall
Change to p2pool/docker-compose directory
Stop and remove all containers: ```docker-compose down```
Remove the p2pool data: ```docker volume rm p2pool```
Remove the monero data: ```docker volume rm monero```
+83
View File
@@ -0,0 +1,83 @@
---
version: '3.4'
networks:
p2pool:
driver: bridge
volumes:
p2pool:
name: ${P2POOL_VOLUME}
monero:
name: ${MONERO_VOLUME}
services:
monero:
image: monero:latest
build:
context: monero
args:
- MONERO_GIT_TAG=$MONERO_GIT_TAG
container_name: p2pool-monero
networks:
- p2pool
ports:
- 18080:18080/tcp
volumes:
- monero:/home/monero/.bitmonero:rw
- /dev/null:/home/monero/.bitmonero/bitmonero.log:rw
- /dev/hugepages:/dev/hugepages:rw
restart: unless-stopped
command: >-
--zmq-pub tcp://0.0.0.0:18083
--disable-dns-checkpoints
--enable-dns-blocklist
--non-interactive
--p2p-bind-ip=0.0.0.0
--p2p-bind-port=18080
--rpc-bind-ip=0.0.0.0
--rpc-bind-port=18081
--confirm-external-bind
${PRUNE_NODE}
p2pool:
image: p2pool:latest
build: ../
container_name: p2pool-p2pool
networks:
- p2pool
ports:
- ${P2POOL_STRATUM_PORT}:3333/tcp
- 37889:37889/tcp
volumes:
- p2pool:/home/p2pool/.p2pool:rw
- /dev/null:/home/p2pool/.p2pool/p2pool.log:rw
- /dev/hugepages:/dev/hugepages:rw
depends_on:
- monero
restart: unless-stopped
command: >-
--host monero
--wallet ${WALLET_ADDRESS}
--loglevel ${P2POOL_LOGLEVEL}
xmrig:
image: xmrig:latest
build: xmrig
container_name: p2pool-xmrig
networks:
- p2pool
privileged: true
volumes:
- /dev:/dev:ro
- /lib/modules:/lib/modules:ro
- /dev/hugepages:/dev/hugepages:rw
depends_on:
- p2pool
restart: unless-stopped
command: >-
${FIXED_MINING_DIFFICULTY}
${NUM_MINING_CPU}
--randomx-1gb-pages
-o p2pool:3333
+79
View File
@@ -0,0 +1,79 @@
FROM ubuntu:latest
ARG MONERO_GIT_TAG="latest"
RUN set -e && \
apt-get update -q -y --no-install-recommends && \
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
git \
ca-certificates \
build-essential \
pkg-config \
cmake \
libuv1-dev \
libzmq3-dev \
libsodium-dev \
libpgm-dev \
libnorm-dev \
libgss-dev \
libssl-dev \
libzmq3-dev \
libunbound-dev \
libsodium-dev \
libunwind8-dev \
liblzma-dev \
libreadline6-dev \
libldns-dev \
libexpat1-dev \
libpgm-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 \
ccache \
doxygen \
graphviz
WORKDIR /usr/src
RUN git clone --recursive 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 release-static -j$(nproc)
# ---
FROM ubuntu:latest
COPY --from=0 /usr/src/monero/build/Linux/*/release/bin/* /
RUN set -e && \
apt-get update -q -y --no-install-recommends && \
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
libgssapi-krb5-2 \
&& \
apt-get clean
RUN groupadd -r monero -g 1000 && \
useradd -u 1000 -r -g monero -s /sbin/nologin -c "monero node user" monero
RUN mkdir -p /home/monero/.bitmonero && \
chown monero.monero /home/monero /home/monero/.bitmonero
USER monero
EXPOSE 18080 18081 18083
VOLUME /home/monero/.bitmonero
WORKDIR /home/monero
ENTRYPOINT ["/monerod"]
+37
View File
@@ -0,0 +1,37 @@
FROM ubuntu:latest
RUN set -e && \
apt-get update -q -y --no-install-recommends && \
DEBIAN_FRONTEND="noninteractive" apt-get install -q -y --no-install-recommends \
git \
build-essential \
ca-certificates \
cmake \
libuv1-dev \
libssl-dev \
libhwloc-dev
WORKDIR /usr/src
RUN git clone https://github.com/xmrig/xmrig.git && \
mkdir xmrig/build && \
cd xmrig/build && \
cmake .. && \
make -j$(nproc)
# ---
FROM ubuntu:latest
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 \
libhwloc15 \
&& \
apt-get clean
WORKDIR /
ENTRYPOINT ["/xmrig"]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -1002,7 +1002,7 @@ void BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
m_poolBlockTemplate->m_nonce = nonce;
m_poolBlockTemplate->m_extraNonce = extra_nonce;
memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_nonceOffset, &nonce, NONCE_SIZE);
memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_extraNonceOffsetInTemplate, &extra_nonce, NONCE_SIZE);
memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_extraNonceOffsetInTemplate, &extra_nonce, EXTRA_NONCE_SIZE);
SideChain& side_chain = m_pool->side_chain();
@@ -1018,7 +1018,7 @@ void BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
}
hash pow_hash;
if (!check.get_pow_hash(m_pool->hasher(), m_seedHash, pow_hash)) {
if (!check.get_pow_hash(m_pool->hasher(), check.m_txinGenHeight, m_seedHash, pow_hash)) {
LOGERR(1, "PoW check failed for the sidechain block. Fix it! ");
}
else if (!check.m_difficulty.check_pow(pow_hash)) {
+44 -5
View File
@@ -21,6 +21,7 @@
#include "p2pool.h"
#include "stratum_server.h"
#include "p2p_server.h"
#include "miner.h"
#include "side_chain.h"
#include <iostream>
@@ -69,7 +70,7 @@ typedef struct cmd {
cmdfunc *func;
} cmd;
static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_exit;
static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_outpeers, do_inpeers, do_start_mining, do_stop_mining, do_exit;
static cmd cmds[] = {
{ STRCONST("help"), "", "display list of commands", do_help },
@@ -78,17 +79,20 @@ static cmd cmds[] = {
{ STRCONST("addpeers"), "<peeraddr>", "add peer", do_addpeers },
{ STRCONST("droppeers"), "", "disconnect all peers", do_droppeers },
{ STRCONST("peers"), "", "show all peers", do_showpeers },
{ STRCONST("outpeers"), "", "set maximum number of outgoing connections", do_outpeers },
{ STRCONST("inpeers"), "", "set maximum number of incoming connections", do_inpeers },
{ STRCONST("start_mining"), "<threads>", "start mining", do_start_mining },
{ STRCONST("stop_mining"), "", "stop mining", do_stop_mining },
{ STRCONST("exit"), "", "terminate p2pool", do_exit },
{ STRCNULL, NULL, NULL, NULL }
};
static int do_help(p2pool * /* m_pool */, const char * /* args */)
{
int i;
LOGINFO(0, "List of commands");
for (i=0; cmds[i].name.len; i++)
for (int i = 0; cmds[i].name.len; ++i) {
LOGINFO(0, cmds[i].name.str << " " << cmds[i].arg << "\t" << cmds[i].descr);
}
return 0;
}
@@ -101,13 +105,16 @@ static int do_status(p2pool *m_pool, const char * /* args */)
if (m_pool->p2p_server()) {
m_pool->p2p_server()->print_status();
}
if (m_pool->miner()) {
m_pool->miner()->print_status();
}
bkg_jobs_tracker.print_status();
return 0;
}
static int do_loglevel(p2pool * /* m_pool */, const char *args)
{
int level = atoi(args);
int level = strtol(args, nullptr, 10);
level = std::min(std::max(level, 0), log::MAX_GLOBAL_LOG_LEVEL);
log::GLOBAL_LOG_LEVEL = level;
LOGINFO(0, "log level set to " << level);
@@ -138,6 +145,38 @@ static int do_showpeers(p2pool* m_pool, const char* /* args */)
return 0;
}
static int do_outpeers(p2pool* m_pool, const char* args)
{
if (m_pool->p2p_server()) {
m_pool->p2p_server()->set_max_outgoing_peers(strtoul(args, nullptr, 10));
LOGINFO(0, "max outgoing peers set to " << m_pool->p2p_server()->max_outgoing_peers());
}
return 0;
}
static int do_inpeers(p2pool* m_pool, const char* args)
{
if (m_pool->p2p_server()) {
m_pool->p2p_server()->set_max_incoming_peers(strtoul(args, nullptr, 10));
LOGINFO(0, "max incoming peers set to " << m_pool->p2p_server()->max_incoming_peers());
}
return 0;
}
static int do_start_mining(p2pool* m_pool, const char* args)
{
uint32_t threads = strtoul(args, nullptr, 10);
threads = std::min(std::max(threads, 1u), 64u);
m_pool->start_mining(threads);
return 0;
}
static int do_stop_mining(p2pool* m_pool, const char* /*args*/)
{
m_pool->stop_mining();
return 0;
}
static int do_exit(p2pool *m_pool, const char * /* args */)
{
bkg_jobs_tracker.wait();
+20 -2
View File
@@ -32,9 +32,12 @@ namespace {
class RandomBytes
{
public:
RandomBytes() : rd(), rng(rd()), dist(0, 255)
RandomBytes() : rng(s), dist(0, 255)
{
uv_mutex_init_checked(&m);
// Diffuse the initial state in case it has low quality
rng.discard(10000);
}
~RandomBytes()
@@ -54,7 +57,22 @@ public:
private:
uv_mutex_t m;
std::random_device rd;
// Fills the whole initial MT19937-64 state with non-deterministic random numbers
struct SeedSequence
{
using result_type = std::random_device::result_type;
template<typename T>
static void generate(T begin, T end)
{
std::random_device rd;
for (T i = begin; i != end; ++i) {
*i = rd();
}
}
};
SeedSequence s;
std::mt19937_64 rng;
std::uniform_int_distribution<> dist;
};
+2 -2
View File
@@ -25,7 +25,7 @@ static constexpr char log_category_prefix[] = "JSONRPCRequest ";
namespace p2pool {
JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb)
JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop)
: m_socket{}
, m_connect{}
, m_write{}
@@ -38,7 +38,7 @@ JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, C
{
m_readBuf[0] = '\0';
uv_tcp_init(uv_default_loop_checked(), &m_socket);
uv_tcp_init(loop ? loop : uv_default_loop_checked(), &m_socket);
uv_tcp_nodelay(&m_socket, 1);
sockaddr_storage addr;
+6 -5
View File
@@ -26,20 +26,21 @@ public:
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb)
{
// It will be deleted in one of the tcp callbacks eventually
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), nullptr);
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), nullptr, nullptr);
if (!r->m_valid) {
delete r;
}
}
template<typename T, typename U>
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb, U&& close_cb)
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb, U&& close_cb, uv_loop_t* loop = nullptr)
{
// It will be deleted in one of the tcp callbacks eventually
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), new Callback<U>(std::move(close_cb)));
CallbackBase* close_callback = new Callback<U>(std::move(close_cb));
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), close_callback, loop);
if (!r->m_valid) {
constexpr char err[] = "internal error";
close_cb(err, sizeof(err) - 1);
(*close_callback)(err, sizeof(err) - 1);
delete r;
}
}
@@ -62,7 +63,7 @@ private:
T m_cb;
};
JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb);
JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop);
~JSONRPCRequest();
static void on_connect(uv_connect_t* req, int status);
+6 -1
View File
@@ -65,7 +65,12 @@ public:
uv_cond_init(&m_cond);
uv_mutex_init(&m_mutex);
uv_thread_create(&m_worker, run_wrapper, this);
const int err = uv_thread_create(&m_worker, run_wrapper, this);
if (err) {
fprintf(stderr, "failed to start logger thread (%s), aborting\n", uv_err_name(err));
abort();
}
do {} while (!worker_started);
+9 -1
View File
@@ -36,14 +36,22 @@ static void usage()
"--loglevel Verbosity of the log, integer number between 0 and %d\n"
"--config Name of the p2pool config file\n"
"--data-api Path to the p2pool JSON data (use it in tandem with an external web-server)\n"
"--stratum-api Enable /local/ path in api path for Stratum Server statistics\n"
"--local-api Enable /local/ path in api path for Stratum Server and built-in miner statistics\n"
"--stratum-api An alias for --local-api\n"
"--no-cache Disable p2pool.cache\n"
"--no-color Disable colors in console output\n"
"--no-randomx Disable internal RandomX hasher: p2pool will use RPC calls to monerod to check PoW hashes\n"
"--out-peers N Maximum number of outgoing connections for p2p server (any value between 10 and 1000)\n"
"--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 1000)\n"
"--start-mining N Start built-in miner using N threads (any value between 1 and 64)\n"
"--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from %d to %d.\n"
"--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",
p2pool::VERSION,
p2pool::log::MAX_GLOBAL_LOG_LEVEL,
p2pool::DEFAULT_P2P_PORT,
p2pool::DEFAULT_P2P_PORT_MINI,
#ifdef _WIN32
"p2pool.exe"
#else
+223
View File
@@ -0,0 +1,223 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include "miner.h"
#include "p2pool.h"
#include "stratum_server.h"
#include "block_template.h"
#include "pow_hash.h"
#include "randomx.h"
#include "params.h"
#include "p2pool_api.h"
#include <thread>
static constexpr char log_category_prefix[] = "Miner ";
using namespace std::chrono;
namespace p2pool {
Miner::Miner(p2pool* pool, uint32_t threads)
: m_pool(pool)
, m_threads(threads)
, m_stopped(false)
, m_startTimestamp(high_resolution_clock::now())
, m_nonce(0)
, m_nonceTimestamp(m_startTimestamp)
, m_extraNonce(0xF19E3779U)
, m_totalHashes(0)
, m_job{}
, m_jobIndex(0)
{
on_block(m_pool->block_template());
m_minerThreads.reserve(threads);
for (uint32_t i = 0; i < threads; ++i) {
WorkerData* data = new WorkerData{ this, i + 1, threads, {} };
const int err = uv_thread_create(&data->m_worker, run, data);
if (err) {
LOGERR(1, "failed to start worker thread " << data->m_index << '/' << threads << ", error " << uv_err_name(err));
delete data;
continue;
}
m_minerThreads.push_back(data);
}
}
Miner::~Miner()
{
m_stopped = true;
for (WorkerData* data : m_minerThreads) {
uv_thread_join(&data->m_worker);
delete data;
}
}
void Miner::print_status()
{
const uint32_t hash_count = 0 - m_nonce.load();
const double dt = static_cast<double>(duration_cast<nanoseconds>(high_resolution_clock::now() - m_nonceTimestamp).count()) / 1e9;
const uint64_t hr = (dt > 0.0) ? static_cast<uint64_t>(hash_count / dt) : 0;
LOGINFO(0, "status" <<
"\nThreads = " << m_threads <<
"\nHashrate = " << log::Hashrate(hr)
);
}
void Miner::on_block(const BlockTemplate& block)
{
const uint32_t next_index = m_jobIndex ^ 1;
Job& j = m_job[next_index];
hash seed;
j.m_blobSize = block.get_hashing_blob(m_extraNonce, j.m_blob, j.m_height, j.m_diff, j.m_sidechainDiff, seed, j.m_nonceOffset, j.m_templateId);
const uint32_t hash_count = 0 - m_nonce.exchange(0);
m_jobIndex = next_index;
const auto cur_ts = high_resolution_clock::now();
const double dt = static_cast<double>(duration_cast<nanoseconds>(cur_ts - m_nonceTimestamp).count()) / 1e9;
m_nonceTimestamp = cur_ts;
m_totalHashes += hash_count;
if (m_pool->api() && m_pool->params().m_localStats) {
m_pool->api()->set(p2pool_api::Category::LOCAL, "miner",
[cur_ts, hash_count, dt, this](log::Stream& s)
{
const uint64_t hr = (dt > 0.0) ? static_cast<uint64_t>(hash_count / dt) : 0;
const double time_running = static_cast<double>(duration_cast<milliseconds>(cur_ts - m_startTimestamp).count()) / 1e3;
s << "{\"current_hashrate\":" << hr
<< ",\"total_hashes\":" << m_totalHashes
<< ",\"time_running\":" << time_running
<< ",\"shares_found\":" << m_sharesFound.load()
<< ",\"threads\":" << m_threads
<< "}";
});
}
}
void Miner::run(void* data)
{
WorkerData* d = static_cast<WorkerData*>(data);
LOGINFO(1, "worker thread " << d->m_index << '/' << d->m_count << " started");
make_thread_background();
d->m_miner->run(d);
LOGINFO(1, "worker thread " << d->m_index << '/' << d->m_count << " stopped");
}
void Miner::run(WorkerData* data)
{
RandomX_Hasher_Base* hasher = m_pool->hasher();
randomx_cache* cache = hasher->cache();
randomx_dataset* dataset = hasher->dataset();
if (!cache && !dataset) {
LOGERR(1, "worker thread " << data->m_index << '/' << data->m_count << ": RandomX cache and dataset are not ready");
return;
}
randomx_flags flags = randomx_get_flags();
if (dataset) {
flags |= RANDOMX_FLAG_FULL_MEM;
}
randomx_vm* vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, dataset ? nullptr : cache, dataset);
if (!vm) {
LOGWARN(1, "couldn't allocate RandomX VM using large pages");
vm = randomx_create_vm(flags, dataset ? nullptr : cache, dataset);
if (!vm) {
LOGERR(1, "couldn't allocate RandomX VM");
return;
}
}
uint32_t index = 0;
Job job[2];
uint32_t seed_counter = 0;
bool first = true;
Miner* miner = data->m_miner;
while (!m_stopped) {
if (hasher->seed_counter() != seed_counter) {
LOGINFO(5, "worker thread " << data->m_index << '/' << data->m_count << " paused (waiting for RandomX cache/dataset update)");
hasher->sync_wait();
seed_counter = hasher->seed_counter();
if (flags & RANDOMX_FLAG_FULL_MEM) {
dataset = hasher->dataset();
randomx_vm_set_dataset(vm, dataset);
}
else {
cache = hasher->cache();
randomx_vm_set_cache(vm, cache);
}
LOGINFO(5, "worker thread " << data->m_index << '/' << data->m_count << " resumed");
}
if (first) {
first = false;
memcpy(&job[index], &miner->m_job[miner->m_jobIndex], sizeof(Job));
job[index].set_nonce(miner->m_nonce.fetch_sub(1), miner->m_extraNonce);
randomx_calculate_hash_first(vm, job[index].m_blob, job[index].m_blobSize);
}
const Job& j = job[index];
index ^= 1;
memcpy(&job[index], &miner->m_job[miner->m_jobIndex], sizeof(Job));
job[index].set_nonce(miner->m_nonce.fetch_sub(1), miner->m_extraNonce);
hash h;
randomx_calculate_hash_next(vm, job[index].m_blob, job[index].m_blobSize, &h);
if (j.m_diff.check_pow(h)) {
LOGINFO(0, log::Green() << "worker thread " << data->m_index << '/' << data->m_count << " found a mainchain block, submitting it");
m_pool->submit_block_async(j.m_templateId, j.m_nonce, j.m_extraNonce);
m_pool->block_template().update_tx_keys();
}
if (j.m_sidechainDiff.check_pow(h)) {
LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << j.m_height << ", diff " << j.m_sidechainDiff << ", worker thread " << data->m_index << '/' << data->m_count);
m_pool->submit_sidechain_block(j.m_templateId, j.m_nonce, j.m_extraNonce);
++m_sharesFound;
}
std::this_thread::yield();
}
randomx_destroy_vm(vm);
}
void Miner::Job::set_nonce(uint32_t nonce, uint32_t extra_nonce)
{
m_nonce = nonce;
m_extraNonce = extra_nonce;
uint8_t* p = m_blob + m_nonceOffset;
p[0] = static_cast<uint8_t>(nonce);
p[1] = static_cast<uint8_t>(nonce >> 8);
p[2] = static_cast<uint8_t>(nonce >> 16);
p[3] = static_cast<uint8_t>(nonce >> 24);
}
} // namespace p2pool
+83
View File
@@ -0,0 +1,83 @@
/*
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "uv_util.h"
#include <chrono>
namespace p2pool {
class p2pool;
class BlockTemplate;
class Miner
{
public:
Miner(p2pool* pool, uint32_t threads);
~Miner();
void print_status();
void on_block(const BlockTemplate& block);
private:
static void run(void* data);
p2pool* m_pool;
uint32_t m_threads;
struct WorkerData
{
Miner* m_miner;
uint32_t m_index;
uint32_t m_count;
uv_thread_t m_worker;
};
std::vector<WorkerData*> m_minerThreads;
volatile bool m_stopped;
std::chrono::time_point<std::chrono::high_resolution_clock> m_startTimestamp;
std::atomic<uint32_t> m_nonce;
std::chrono::time_point<std::chrono::high_resolution_clock> m_nonceTimestamp;
const uint32_t m_extraNonce;
uint64_t m_totalHashes;
std::atomic<uint32_t> m_sharesFound;
struct Job
{
uint8_t m_blob[128] = {};
uint32_t m_blobSize = 0;
uint32_t m_templateId = 0;
difficulty_type m_diff = {};
difficulty_type m_sidechainDiff = {};
uint64_t m_height = 0;
size_t m_nonceOffset = 0;
uint32_t m_nonce = 0;
uint32_t m_extraNonce = 0;
void set_nonce(uint32_t nonce, uint32_t extra_nonce);
};
Job m_job[2];
volatile uint32_t m_jobIndex;
void run(WorkerData* data);
};
} // namespace p2pool
+30 -14
View File
@@ -28,9 +28,8 @@
static constexpr char log_category_prefix[] = "P2PServer ";
static constexpr char saved_peer_list_file_name[] = "p2pool_peers.txt";
static const char* seed_nodes[] = {
"seeds.p2pool.io"
};
static const char* seed_nodes[] = { "seeds.p2pool.io", ""};
static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
static constexpr int DEFAULT_BACKLOG = 16;
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
@@ -53,6 +52,9 @@ P2PServer::P2PServer(p2pool* pool)
, m_peerId(m_rng())
, m_peerListLastSaved(0)
{
set_max_outgoing_peers(pool->params().m_maxOutgoingPeers);
set_max_incoming_peers(pool->params().m_maxIncomingPeers);
uv_mutex_init_checked(&m_rngLock);
uv_mutex_init_checked(&m_blockLock);
uv_mutex_init_checked(&m_peerListLock);
@@ -226,8 +228,8 @@ void P2PServer::update_peer_connections()
peer_list = m_peerList;
}
// Try to have at least 10 outgoing connections
for (uint32_t i = m_numConnections - m_numIncomingConnections; (i < 10) && !peer_list.empty();) {
// Try to have at least N outgoing connections (N defaults to 10, can be set via --out-peers command line parameter)
for (uint32_t i = m_numConnections - m_numIncomingConnections; (i < m_maxOutgoingPeers) && !peer_list.empty();) {
const uint64_t k = get_random64() % peer_list.size();
const Peer& peer = peer_list[k];
@@ -368,12 +370,10 @@ void P2PServer::load_peer_list()
{
std::string saved_list;
// Load peers from seed nodes if we're on the default sidechain
if (m_pool->side_chain().is_default()) {
const int p2p_port = DEFAULT_P2P_PORT;
for (size_t i = 0; i < array_size(seed_nodes); ++i) {
LOGINFO(4, "loading peers from " << seed_nodes[i]);
// Load peers from seed nodes if we're on the default or mini sidechain
auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) {
for (size_t i = 0; nodes[i][0]; ++i) {
LOGINFO(4, "loading peers from " << nodes[i]);
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
@@ -381,7 +381,7 @@ void P2PServer::load_peer_list()
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
addrinfo* result;
const int err = getaddrinfo(seed_nodes[i], nullptr, &hints, &result);
const int err = getaddrinfo(nodes[i], nullptr, &hints, &result);
if (err == 0) {
for (addrinfo* r = result; r != NULL; r = r->ai_next) {
const char* addr_str;
@@ -404,7 +404,7 @@ void P2PServer::load_peer_list()
}
if (s.m_pos) {
LOGINFO(4, "added " << static_cast<char*>(buf) << " from " << seed_nodes[i]);
LOGINFO(4, "added " << static_cast<char*>(buf) << " from " << nodes[i]);
if (!saved_list.empty()) {
saved_list += ',';
}
@@ -414,9 +414,16 @@ void P2PServer::load_peer_list()
freeaddrinfo(result);
}
else {
LOGWARN(3, "getaddrinfo failed for " << seed_nodes[i] << ": " << gai_strerror(err));
LOGWARN(3, "getaddrinfo failed for " << nodes[i] << ": " << gai_strerror(err));
}
}
};
if (m_pool->side_chain().is_default()) {
load_from_seed_nodes(seed_nodes, DEFAULT_P2P_PORT);
}
else if (m_pool->side_chain().is_mini()) {
load_from_seed_nodes(seed_nodes_mini, DEFAULT_P2P_PORT_MINI);
}
// Finally load peers from p2pool_peers.txt
@@ -903,6 +910,15 @@ bool P2PServer::P2PClient::on_connect()
{
P2PServer* server = static_cast<P2PServer*>(m_owner);
if (!server) {
return false;
}
if (m_isIncoming && (server->m_numIncomingConnections > server->m_maxIncomingPeers)) {
LOGINFO(5, "Connection from " << log::Gray() << static_cast<char*>(m_addrString) << log::NoColor() << " rejected (incoming connections limit was reached)");
return false;
}
// Don't allow multiple connections to/from the same IP
// server->m_clientsListLock is already locked here
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
+9
View File
@@ -29,6 +29,7 @@ class BlockCache;
static constexpr size_t P2P_BUF_SIZE = 128 * 1024;
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;
class P2PServer : public TCPServer<P2P_BUF_SIZE, P2P_BUF_SIZE>
{
@@ -130,11 +131,19 @@ public:
void show_peers();
size_t peer_list_size() const { return m_peerList.size(); }
uint32_t max_outgoing_peers() const { return m_maxOutgoingPeers; }
uint32_t max_incoming_peers() const { return m_maxIncomingPeers; }
void set_max_outgoing_peers(uint32_t n) { m_maxOutgoingPeers = std::min(std::max(n, 10U), 1000U); }
void set_max_incoming_peers(uint32_t n) { m_maxIncomingPeers = std::min(std::max(n, 10U), 1000U); }
private:
p2pool* m_pool;
BlockCache* m_cache;
bool m_cacheLoaded;
std::string m_initialPeerList;
uint32_t m_maxOutgoingPeers;
uint32_t m_maxIncomingPeers;
uv_rwlock_t m_cachedBlocksLock;
unordered_map<hash, PoolBlock*> m_cachedBlocks;
+57 -20
View File
@@ -27,10 +27,12 @@
#include "side_chain.h"
#include "stratum_server.h"
#include "p2p_server.h"
#include "miner.h"
#include "params.h"
#include "console_commands.h"
#include "crypto.h"
#include "p2pool_api.h"
#include "pool_block.h"
#include <thread>
#include <fstream>
@@ -109,8 +111,25 @@ p2pool::p2pool(int argc, char* argv[])
m_api = m_params->m_apiPath.empty() ? nullptr : new p2pool_api(m_params->m_apiPath, m_params->m_localStats);
m_sideChain = new SideChain(this, type);
m_hasher = new RandomX_Hasher(this);
m_sideChain = new SideChain(this, type, m_params->m_mini ? "mini" : nullptr);
if (m_params->m_p2pAddresses.empty()) {
const int p2p_port = m_sideChain->is_mini() ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT;
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s(buf);
s << "[::]:" << p2p_port << ",0.0.0.0:" << p2p_port << '\0';
m_params->m_p2pAddresses = buf;
}
if (m_params->m_disableRandomX) {
m_hasher = new RandomX_Hasher_RPC(this);
}
else {
m_hasher = new RandomX_Hasher(this);
}
m_blockTemplate = new BlockTemplate(this);
m_mempool = new Mempool();
m_consoleCommands = new ConsoleCommands(this);
@@ -131,9 +150,9 @@ p2pool::~p2pool()
delete m_consoleCommands;
}
bool p2pool::calculate_hash(const void* data, size_t size, const hash& seed, hash& result)
bool p2pool::calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result)
{
return m_hasher->calculate(data, size, seed, result);
return m_hasher->calculate(data, size, height, seed, result);
}
uint64_t p2pool::get_seed_height(uint64_t height)
@@ -321,8 +340,13 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
", reward = " << log::Gray() << log::XMRAmount(data.reward));
if (!sidechain_id.empty()) {
if (side_chain().has_block(sidechain_id)) {
PoolBlock* block = side_chain().find_block(sidechain_id);
if (block) {
LOGINFO(0, log::LightGreen() << "BLOCK FOUND: main chain block at height " << data.height << " was mined by this p2pool" << BLOCK_FOUND);
const uint64_t payout = block->get_payout(params().m_wallet);
if (payout) {
LOGINFO(0, log::LightCyan() << "You received a payout of " << log::LightGreen() << log::XMRAmount(payout) << log::LightCyan() << " in block " << log::LightGreen() << data.height);
}
api_update_block_found(&data);
}
else {
@@ -573,6 +597,9 @@ void p2pool::download_block_headers(uint64_t current_height)
m_ZMQReader = new ZMQReader(m_params->m_host.c_str(), m_params->m_zmqPort, this);
m_stratumServer = new StratumServer(this);
m_p2pServer = new P2PServer(this);
if (m_params->m_minerThreads) {
start_mining(m_params->m_minerThreads);
}
api_update_network_stats();
}
}
@@ -639,22 +666,12 @@ void p2pool::update_median_timestamp()
void p2pool::stratum_on_block()
{
#if 0
uint8_t hashing_blob[128];
uint64_t height;
difficulty_type difficulty;
difficulty_type sidechain_difficulty;
hash seed_hash;
size_t nonce_offset;
uint32_t template_id;
m_blockTemplate->get_hashing_blob(0, hashing_blob, height, difficulty, sidechain_difficulty, seed_hash, nonce_offset, template_id);
submit_block(template_id, 0, 0);
#else
if (m_miner) {
m_miner->on_block(*m_blockTemplate);
}
if (m_stratumServer) {
m_stratumServer->on_block(*m_blockTemplate);
}
#endif
}
void p2pool::get_info()
@@ -811,10 +828,14 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
return;
}
if (version < 0x30008) {
const uint64_t required = m_params->m_disableRandomX ? 0x30009 : 0x30008;
if (version < required) {
const uint64_t version_hi = version >> 16;
const uint64_t version_lo = version & 65535;
LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v3.8");
const uint64_t required_version_hi = required >> 16;
const uint64_t required_version_lo = required & 65535;
LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v" << required_version_hi << '.' << required_version_lo << " (Monero v0.17.3.0 or newer)");
panic();
}
@@ -1193,6 +1214,21 @@ bool p2pool::get_difficulty_at_height(uint64_t height, difficulty_type& diff)
return true;
}
void p2pool::start_mining(uint32_t threads)
{
stop_mining();
m_miner = new Miner(this, threads);
}
void p2pool::stop_mining()
{
Miner* miner = m_miner;
if (miner) {
m_miner = nullptr;
delete miner;
}
}
static void on_signal(uv_signal_t* handle, int signum)
{
p2pool* pool = reinterpret_cast<p2pool*>(handle->data);
@@ -1301,6 +1337,7 @@ int p2pool::run()
bkg_jobs_tracker.wait();
delete m_miner;
delete m_stratumServer;
delete m_p2pServer;
+10 -4
View File
@@ -23,12 +23,13 @@
namespace p2pool {
struct Params;
class RandomX_Hasher;
class RandomX_Hasher_Base;
class BlockTemplate;
class Mempool;
class SideChain;
class StratumServer;
class P2PServer;
class Miner;
class ConsoleCommands;
class p2pool_api;
class ZMQReader;
@@ -51,13 +52,14 @@ public:
p2pool_api* api() const { return m_api; }
RandomX_Hasher* hasher() const { return m_hasher; }
bool calculate_hash(const void* data, size_t size, const hash& seed, hash& result);
RandomX_Hasher_Base* hasher() const { return m_hasher; }
bool calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result);
static uint64_t get_seed_height(uint64_t height);
bool get_seed(uint64_t height, hash& seed) const;
StratumServer* stratum_server() const { return m_stratumServer; }
P2PServer* p2p_server() const { return m_p2pServer; }
Miner* miner() const { return m_miner; }
virtual void handle_tx(TxMempoolData& tx) override;
virtual void handle_miner_data(MinerData& data) override;
@@ -78,6 +80,9 @@ public:
bool get_difficulty_at_height(uint64_t height, difficulty_type& diff);
void start_mining(uint32_t threads);
void stop_mining();
time_t zmq_last_active() const { return m_zmqLastActive; }
time_t start_time() const { return m_startTime; }
@@ -97,7 +102,7 @@ private:
p2pool_api* m_api;
SideChain* m_sideChain;
RandomX_Hasher* m_hasher;
RandomX_Hasher_Base* m_hasher;
BlockTemplate* m_blockTemplate;
MinerData m_minerData;
bool m_updateSeed;
@@ -155,6 +160,7 @@ private:
std::atomic<uint32_t> m_serversStarted{ 0 };
StratumServer* m_stratumServer = nullptr;
P2PServer* m_p2pServer = nullptr;
Miner* m_miner = nullptr;
ConsoleCommands* m_consoleCommands;
+24 -14
View File
@@ -30,11 +30,11 @@ Params::Params(int argc, char* argv[])
}
if ((strcmp(argv[i], "--rpc-port") == 0) && (i + 1 < argc)) {
m_rpcPort = static_cast<uint32_t>(atoi(argv[++i]));
m_rpcPort = strtoul(argv[++i], nullptr, 10);
}
if ((strcmp(argv[i], "--zmq-port") == 0) && (i + 1 < argc)) {
m_zmqPort = static_cast<uint32_t>(atoi(argv[++i]));
m_zmqPort = strtoul(argv[++i], nullptr, 10);
}
if (strcmp(argv[i], "--light-mode") == 0) {
@@ -58,7 +58,7 @@ Params::Params(int argc, char* argv[])
}
if ((strcmp(argv[i], "--loglevel") == 0) && (i + 1 < argc)) {
const int level = std::min(std::max(atoi(argv[++i]), 0), log::MAX_GLOBAL_LOG_LEVEL);
const int level = std::min(std::max<int>(strtol(argv[++i], nullptr, 10), 0), log::MAX_GLOBAL_LOG_LEVEL);
log::GLOBAL_LOG_LEVEL = level;
}
@@ -70,7 +70,7 @@ Params::Params(int argc, char* argv[])
m_apiPath = argv[++i];
}
if (strcmp(argv[i], "--stratum-api") == 0) {
if ((strcmp(argv[i], "--local-api") == 0) || (strcmp(argv[i], "--stratum-api") == 0)) {
m_localStats = true;
}
@@ -81,6 +81,26 @@ Params::Params(int argc, char* argv[])
if (strcmp(argv[i], "--no-color") == 0) {
log::CONSOLE_COLORS = false;
}
if (strcmp(argv[i], "--no-randomx") == 0) {
m_disableRandomX = true;
}
if ((strcmp(argv[i], "--out-peers") == 0) && (i + 1 < argc)) {
m_maxOutgoingPeers = std::min(std::max(strtoul(argv[++i], nullptr, 10), 10UL), 1000UL);
}
if ((strcmp(argv[i], "--in-peers") == 0) && (i + 1 < argc)) {
m_maxIncomingPeers = std::min(std::max(strtoul(argv[++i], nullptr, 10), 10UL), 1000UL);
}
if ((strcmp(argv[i], "--start-mining") == 0) && (i + 1 < argc)) {
m_minerThreads = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 64UL);
}
if (strcmp(argv[i], "--mini") == 0) {
m_mini = true;
}
}
if (m_stratumAddresses.empty()) {
@@ -92,16 +112,6 @@ Params::Params(int argc, char* argv[])
m_stratumAddresses = buf;
}
if (m_p2pAddresses.empty()) {
const int p2p_port = DEFAULT_P2P_PORT;
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s(buf);
s << "[::]:" << p2p_port << ",0.0.0.0:" << p2p_port << '\0';
m_p2pAddresses = buf;
}
}
bool Params::ok() const
+5
View File
@@ -39,6 +39,11 @@ struct Params
std::string m_apiPath;
bool m_localStats = false;
bool m_blockCache = true;
bool m_disableRandomX = false;
uint32_t m_maxOutgoingPeers = 10;
uint32_t m_maxIncomingPeers = 1000;
uint32_t m_minerThreads = 0;
bool m_mini = false;
};
} // namespace p2pool
+14 -2
View File
@@ -225,7 +225,7 @@ void PoolBlock::serialize_sidechain_data()
writeVarint(m_cumulativeDifficulty.hi, m_sideChainData);
}
bool PoolBlock::get_pow_hash(RandomX_Hasher* hasher, const hash& seed_hash, hash& pow_hash)
bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash)
{
alignas(8) uint8_t hashes[HASH_SIZE * 3];
@@ -295,7 +295,19 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher* hasher, const hash& seed_hash, hash
writeVarint(count, [&blob, &blob_size](uint8_t b) { blob[blob_size++] = b; });
return hasher->calculate(blob, blob_size, seed_hash, pow_hash);
return hasher->calculate(blob, blob_size, height, seed_hash, pow_hash);
}
uint64_t PoolBlock::get_payout(const Wallet& w) const
{
for (size_t i = 0, n = m_outputs.size(); i < n; ++i) {
hash eph_public_key;
if ((w.get_eph_public_key(m_txkeySec, i, eph_public_key)) && (eph_public_key == m_outputs[i].m_ephPublicKey)) {
return m_outputs[i].m_reward;
}
}
return 0;
}
} // namespace p2pool
+4 -2
View File
@@ -28,7 +28,7 @@
namespace p2pool {
class RandomX_Hasher;
class RandomX_Hasher_Base;
class SideChain;
/*
@@ -136,7 +136,9 @@ struct PoolBlock
void serialize_sidechain_data();
int deserialize(const uint8_t* data, size_t size, SideChain& sidechain);
bool get_pow_hash(RandomX_Hasher* hasher, const hash& seed_hash, hash& pow_hash);
bool get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash);
uint64_t get_payout(const Wallet& w) const;
};
} // namespace p2pool
+121 -8
View File
@@ -22,6 +22,9 @@
#include "randomx.h"
#include "configuration.h"
#include "virtual_machine.hpp"
#include "json_rpc_request.h"
#include "json_parsers.h"
#include <rapidjson/document.h>
#include <thread>
static constexpr char log_category_prefix[] = "RandomX_Hasher ";
@@ -34,7 +37,7 @@ RandomX_Hasher::RandomX_Hasher(p2pool* pool)
, m_dataset(nullptr)
, m_seed{}
, m_index(0)
, m_setSeedCounter(0)
, m_seedCounter(0)
{
uint64_t memory_allocated = 0;
@@ -116,6 +119,10 @@ RandomX_Hasher::~RandomX_Hasher()
void RandomX_Hasher::set_seed_async(const hash& seed)
{
if (m_seed[m_index] == seed) {
return;
}
struct Work
{
p2pool* pool;
@@ -124,10 +131,7 @@ void RandomX_Hasher::set_seed_async(const hash& seed)
uv_work_t req;
};
Work* work = new Work{};
work->pool = m_pool;
work->hasher = this;
work->seed = seed;
Work* work = new Work{ m_pool, this, seed, {} };
work->req.data = work;
const int err = uv_queue_work(uv_default_loop_checked(), &work->req,
@@ -164,7 +168,7 @@ void RandomX_Hasher::set_seed(const hash& seed)
WriteLock lock(m_datasetLock);
uv_rwlock_wrlock(&m_cacheLock);
m_setSeedCounter.fetch_add(1);
m_seedCounter.fetch_add(1);
if (m_seed[m_index] == seed) {
uv_rwlock_wrunlock(&m_cacheLock);
@@ -266,7 +270,7 @@ void RandomX_Hasher::set_seed(const hash& seed)
void RandomX_Hasher::set_old_seed(const hash& seed)
{
// set_seed() must go first, wait for it
while (m_setSeedCounter.load() == 0) {
while (m_seedCounter.load() == 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
@@ -302,7 +306,13 @@ void RandomX_Hasher::set_old_seed(const hash& seed)
LOGINFO(1, log::LightCyan() << "old cache updated");
}
bool RandomX_Hasher::calculate(const void* data, size_t size, const hash& seed, hash& result)
void RandomX_Hasher::sync_wait()
{
ReadLock lock(m_datasetLock);
ReadLock lock2(m_cacheLock);
}
bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*/, const hash& seed, hash& result)
{
// First try to use the dataset if it's ready
if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) {
@@ -348,4 +358,107 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, const hash& seed,
return false;
}
RandomX_Hasher_RPC::RandomX_Hasher_RPC(p2pool* pool)
: m_pool(pool)
, m_loopThread{}
{
int err = uv_loop_init(&m_loop);
if (err) {
LOGERR(1, "failed to create event loop, error " << uv_err_name(err));
panic();
}
uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown);
uv_async_init(&m_loop, &m_kickTheLoopAsync, nullptr);
m_shutdownAsync.data = this;
uv_mutex_init_checked(&m_requestMutex);
uv_mutex_init_checked(&m_condMutex);
err = uv_cond_init(&m_cond);
if (err) {
LOGERR(1, "failed to create cond, error " << uv_err_name(err));
panic();
}
err = uv_thread_create(&m_loopThread, loop, this);
if (err) {
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
panic();
}
}
RandomX_Hasher_RPC::~RandomX_Hasher_RPC()
{
uv_async_send(&m_shutdownAsync);
uv_thread_join(&m_loopThread);
uv_mutex_destroy(&m_requestMutex);
uv_mutex_destroy(&m_condMutex);
uv_cond_destroy(&m_cond);
LOGINFO(1, "stopped");
}
void RandomX_Hasher_RPC::loop(void* data)
{
LOGINFO(1, "event loop started");
RandomX_Hasher_RPC* hasher = static_cast<RandomX_Hasher_RPC*>(data);
uv_run(&hasher->m_loop, UV_RUN_DEFAULT);
uv_loop_close(&hasher->m_loop);
LOGINFO(1, "event loop stopped");
}
bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t height, const hash& /*seed*/, hash& h)
{
MutexLock lock(m_requestMutex);
const uint8_t* data = reinterpret_cast<const uint8_t*>(data_ptr);
const uint8_t major_version = data[0];
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s(buf);
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"calc_pow\",\"params\":{\"major_version\":" << major_version <<
",\"height\":" << height <<
",\"block_blob\":\"" << log::hex_buf(data, size) << '"' <<
",\"seed_hash\":\"\"}}";
volatile int result = 0;
volatile bool done = false;
JSONRPCRequest::call(m_pool->params().m_host.c_str(), m_pool->params().m_rpcPort, buf,
[&result, &h](const char* data, size_t size)
{
rapidjson::Document doc;
if (doc.Parse(data, size).HasParseError() || !parseValue(doc, "result", h)) {
LOGWARN(3, "RPC calc_pow: invalid JSON response (parse error)");
result = -1;
return;
}
result = 1;
},
[this, &result, &done](const char* data, size_t size)
{
if (size > 0) {
LOGWARN(3, "RPC calc_pow: server returned error " << log::const_buf(data, size));
result = -1;
}
MutexLock lock2(m_condMutex);
done = true;
uv_cond_signal(&m_cond);
}, &m_loop);
uv_async_send(&m_kickTheLoopAsync);
{
MutexLock lock2(m_condMutex);
while (!done) {
uv_cond_wait(&m_cond, &m_condMutex);
}
}
return result > 0;
}
} // namespace p2pool
+57 -5
View File
@@ -27,18 +27,39 @@ namespace p2pool {
class p2pool;
class RandomX_Hasher
class RandomX_Hasher_Base
{
public:
virtual ~RandomX_Hasher_Base() {}
virtual void set_seed_async(const hash&) {}
virtual void set_old_seed(const hash&) {}
virtual randomx_cache* cache() const { return nullptr; }
virtual randomx_dataset* dataset() const { return nullptr; }
virtual uint32_t seed_counter() const { return 0; }
virtual void sync_wait() {}
virtual bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) = 0;
};
class RandomX_Hasher : public RandomX_Hasher_Base
{
public:
explicit RandomX_Hasher(p2pool* pool);
~RandomX_Hasher();
void set_seed_async(const hash& seed);
void set_seed_async(const hash& seed) override;
void set_seed(const hash& seed);
void set_old_seed(const hash& seed);
void set_old_seed(const hash& seed) override;
bool calculate(const void* data, size_t size, const hash& seed, hash& result);
randomx_cache* cache() const override { return m_cache[m_index]; }
randomx_dataset* dataset() const override { return m_dataset; }
uint32_t seed_counter() const override { return m_seedCounter.load(); }
void sync_wait() override;
bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) override;
private:
@@ -67,7 +88,38 @@ private:
hash m_seed[2];
uint32_t m_index;
std::atomic<uint32_t> m_setSeedCounter;
std::atomic<uint32_t> m_seedCounter;
};
class RandomX_Hasher_RPC : public RandomX_Hasher_Base
{
public:
explicit RandomX_Hasher_RPC(p2pool* pool);
~RandomX_Hasher_RPC();
bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) override;
private:
static void loop(void* data);
p2pool* m_pool;
uv_mutex_t m_requestMutex;
uv_loop_t m_loop;
uv_thread_t m_loopThread;
uv_mutex_t m_condMutex;
uv_cond_t m_cond;
uv_async_t m_shutdownAsync;
uv_async_t m_kickTheLoopAsync;
static void on_shutdown(uv_async_t* async)
{
RandomX_Hasher_RPC* server = reinterpret_cast<RandomX_Hasher_RPC*>(async->data);
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_shutdownAsync), nullptr);
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_kickTheLoopAsync), nullptr);
}
};
} // namespace p2pool
+26 -6
View File
@@ -51,9 +51,8 @@ static_assert(1 <= UNCLE_BLOCK_DEPTH && UNCLE_BLOCK_DEPTH <= 10, "Invalid UNCLE_
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 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 };
SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
: m_pool(pool)
@@ -97,11 +96,16 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
<< m_unclePenalty << '\0';
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";
// Hardcoded default consensus ID
if (memcmp(buf, default_config, sizeof(default_config) - 1) == 0) {
m_consensusId.assign(default_consensus_id, default_consensus_id + HASH_SIZE);
}
// Hardcoded mini consensus ID
else if (memcmp(buf, mini_config, sizeof(mini_config) - 1) == 0) {
m_consensusId.assign(mini_consensus_id, mini_consensus_id + HASH_SIZE);
}
else {
const randomx_flags flags = randomx_get_flags();
randomx_cache* cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
@@ -429,7 +433,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
}
hash pow_hash;
if (!block.get_pow_hash(m_pool->hasher(), seed, pow_hash)) {
if (!block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash)) {
LOGWARN(3, "add_external_block: couldn't get PoW hash for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight << ". Ignoring it.");
unsee_block(block);
return true;
@@ -477,6 +481,11 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
m_watchBlockSidechainId = {};
data = m_watchBlock;
block_found = true;
const uint64_t payout = block.get_payout(m_pool->params().m_wallet);
if (payout) {
LOGINFO(0, log::LightCyan() << "You received a payout of " << log::LightGreen() << log::XMRAmount(payout) << log::LightCyan() << " in block " << log::LightGreen() << data.height);
}
}
}
@@ -532,10 +541,16 @@ void SideChain::add_block(const PoolBlock& block)
m_seenWallets[new_block->m_minerWallet.spend_public_key()] = new_block->m_localTimestamp;
}
bool SideChain::has_block(const hash& id)
PoolBlock* SideChain::find_block(const hash& id)
{
MutexLock lock(m_sidechainLock);
return m_blocksById.find(id) != m_blocksById.end();
auto it = m_blocksById.find(id);
if (it != m_blocksById.end()) {
return it->second;
}
return nullptr;
}
void SideChain::watch_mainchain_block(const ChainMain& data, const hash& possible_id)
@@ -785,6 +800,11 @@ bool SideChain::is_default() const
return (memcmp(m_consensusId.data(), default_consensus_id, HASH_SIZE) == 0);
}
bool SideChain::is_mini() const
{
return (memcmp(m_consensusId.data(), mini_consensus_id, HASH_SIZE) == 0);
}
bool SideChain::split_reward(uint64_t reward, const std::vector<MinerShare>& shares, std::vector<uint64_t>& rewards)
{
const size_t num_shares = shares.size();
+2 -1
View File
@@ -51,7 +51,7 @@ public:
void add_block(const PoolBlock& block);
void get_missing_blocks(std::vector<hash>& missing_blocks);
bool has_block(const hash& id);
PoolBlock* find_block(const hash& id);
void watch_mainchain_block(const ChainMain& data, const hash& possible_id);
bool get_block_blob(const hash& id, std::vector<uint8_t>& blob);
@@ -71,6 +71,7 @@ public:
uint64_t miner_count();
time_t last_updated() const;
bool is_default() const;
bool is_mini() const;
const PoolBlock* chainTip() const { return m_chainTip; }
+17 -2
View File
@@ -516,6 +516,8 @@ void StratumServer::on_blobs_ready()
size_t numClientsProcessed = 0;
uint32_t extra_nonce = 0;
const time_t cur_time = time(nullptr);
{
MutexLock lock2(m_clientsListLock);
@@ -523,7 +525,12 @@ void StratumServer::on_blobs_ready()
++numClientsProcessed;
if (!client->m_rpcId) {
// Not logged in yet, on_login() will send the job to this client
// Not logged in yet, on_login() will send the job to this client. Also close inactive connections.
if (cur_time >= client->m_connectedTime + 10) {
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " didn't send login data");
client->ban(DEFAULT_BAN_TIME);
client->close();
}
continue;
}
@@ -661,7 +668,7 @@ void StratumServer::on_share_found(uv_work_t* req)
}
hash pow_hash;
if (!pool->calculate_hash(blob, blob_size, seed_hash, pow_hash)) {
if (!pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash)) {
LOGWARN(3, "client " << static_cast<char*>(client->m_addrString) << " couldn't check share PoW");
share->m_result = SubmittedShare::Result::COULDNT_CHECK_POW;
return;
@@ -760,6 +767,7 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
StratumServer::StratumClient::StratumClient()
: m_rpcId(0)
, m_connectedTime(0)
, m_jobs{}
, m_perConnectionJobId(0)
, m_customDiff{}
@@ -776,12 +784,19 @@ void StratumServer::StratumClient::reset()
{
Client::reset();
m_rpcId = 0;
m_connectedTime = 0;
memset(m_jobs, 0, sizeof(m_jobs));
m_perConnectionJobId = 0;
m_customDiff = {};
m_customUser.clear();
}
bool StratumServer::StratumClient::on_connect()
{
m_connectedTime = time(nullptr);
return true;
}
bool StratumServer::StratumClient::on_read(char* data, uint32_t size)
{
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + sizeof(m_readBuf))) {
+2 -1
View File
@@ -45,7 +45,7 @@ public:
static Client* allocate() { return new StratumClient(); }
void reset() override;
bool on_connect() override { return true; }
bool on_connect() override;
bool on_read(char* data, uint32_t size) override;
bool process_request(char* data, uint32_t size);
@@ -53,6 +53,7 @@ public:
bool process_submit(rapidjson::Document& doc, uint32_t id);
uint32_t m_rpcId;
time_t m_connectedTime;
uv_mutex_t m_jobsLock;
-1
View File
@@ -76,7 +76,6 @@ public:
Client* m_next;
uv_tcp_t m_socket;
uv_write_t m_write;
uv_connect_t m_connectRequest;
bool m_isV6;
+1 -1
View File
@@ -564,6 +564,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
TCPServer* server = static_cast<TCPServer*>(data);
uv_run(&server->m_loop, UV_RUN_DEFAULT);
uv_loop_close(&server->m_loop);
LOGINFO(1, "event loop stopped");
server->m_loopStopped = true;
}
@@ -798,7 +799,6 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::reset()
m_prev = nullptr;
m_next = nullptr;
memset(&m_socket, 0, sizeof(m_socket));
memset(&m_write, 0, sizeof(m_write));
memset(&m_connectRequest, 0, sizeof(m_connectRequest));
m_isV6 = false;
m_isIncoming = false;
+1 -1
View File
@@ -32,7 +32,7 @@ namespace p2pool {
#define STR2(X) STR(X)
#define STR(X) #X
const char* VERSION = "v1.3.1 (built"
const char* VERSION = "v1.7 (built"
#if defined(__clang__)
" with clang/" __clang_version__
#elif defined(__GNUC__)
+1
View File
@@ -86,6 +86,7 @@ set(SOURCES
../src/log.cpp
../src/memory_leak_debug.cpp
../src/mempool.cpp
../src/miner.cpp
../src/p2p_server.cpp
../src/p2pool.cpp
../src/p2pool_api.cpp
+2 -2
View File
@@ -91,7 +91,7 @@ TEST(pool_block, deserialize)
hasher.set_seed(seed);
hash pow_hash;
ASSERT_EQ(b.get_pow_hash(&hasher, seed, pow_hash), true);
ASSERT_EQ(b.get_pow_hash(&hasher, 0, seed, pow_hash), true);
std::stringstream s;
s << pow_hash;
@@ -125,7 +125,7 @@ TEST(pool_block, verify)
p += n;
sidechain.add_block(b);
ASSERT_TRUE(sidechain.has_block(b.m_sidechainId));
ASSERT_TRUE(sidechain.find_block(b.m_sidechainId) != nullptr);
}
const PoolBlock* tip = sidechain.chainTip();