Compare commits

..

25 Commits

Author SHA1 Message Date
SChernykh d8ddaf80c8 p2pool v4.13 2025-12-18 12:26:42 +01:00
SChernykh 2dc091f3d4 Build scripts: updated versions 2025-12-17 20:42:15 +01:00
SChernykh 55cd2c9ae1 CI: disabled type sanitizer sync test 2025-12-16 22:17:29 +01:00
SChernykh 53cecac65b CI: added type sanitizer sync test 2025-12-16 19:19:54 +01:00
QuocViet Le d9de512b92 docs(nano): update documentation for nano (#386) 2025-12-11 20:17:49 +01:00
SChernykh 1bdf562967 Build scripts: updated versions 2025-12-07 20:12:17 +01:00
SChernykh d0daa6ec41 Sync test: ignore ZMQ reader errors 2025-12-05 21:20:25 +01:00
hinto-janai 1eb93fcd6b Edits to Gupax references (#387) 2025-12-02 10:22:34 +01:00
SChernykh 1cb4940960 Sync test: ignore node connection errors 2025-11-28 15:59:04 +01:00
SChernykh d5025965b4 Sync test: ignore random ZMQ disconnects 2025-11-25 18:17:33 +01:00
SChernykh 6aba1edaf8 Updated BoringSSL to v0.20251124.0 2025-11-25 11:36:15 +01:00
SChernykh 1166f31d07 RandomX: send seed when calling RPC (it's faster on monerod side) 2025-11-24 13:18:13 +01:00
SChernykh 3d2c9910f8 P2P: give peers from --addpeers a 2-second headstart before connecting to other peers 2025-11-22 13:24:03 +01:00
SChernykh 3584910baa Fixed reading the last line of config 2025-11-22 09:23:03 +01:00
SChernykh 8230040b76 Fixed CI errors 2025-11-21 21:20:20 +01:00
SChernykh de28201edc Added support for params config file 2025-11-21 20:13:13 +01:00
SChernykh d9cea1cfc3 Refactored command line parsing (part 2) 2025-11-21 18:15:57 +01:00
SChernykh 321d698be5 Refactored command line parsing 2025-11-21 13:22:39 +01:00
SChernykh 44a668cb15 Fixed onion connection counter 2025-11-20 17:19:40 +01:00
SChernykh 8151a5a537 Added --log-file command line parameter 2025-11-20 16:42:34 +01:00
SChernykh b81a582154 Build scripts: updated versions 2025-11-20 14:30:02 +01:00
SChernykh ee931ee178 Build scripts: updated clang to 21.1.6 2025-11-18 16:10:18 +01:00
SChernykh dbf0e58ee5 Build scripts: updated versions 2025-11-17 16:50:49 +01:00
SChernykh 86e9e90744 Updated BoringSSL patch 2025-11-12 13:21:08 +01:00
SChernykh dec45532f8 Updated BoringSSL to v0.20251110.0 2025-11-12 10:00:31 +01:00
38 changed files with 674 additions and 306 deletions
+58
View File
@@ -286,6 +286,64 @@ jobs:
build/*.log
build/data/
sync-test-ubuntu-tysan:
if: false # disabled because it generates a flood of type aliasing errors
timeout-minutes: 60
runs-on: ubuntu-22.04
steps:
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev
- name: Install clang
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21 all
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build p2pool
run: |
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang-21 -DCMAKE_CXX_COMPILER=clang++-21 -DDEV_TEST_SYNC=ON -DDEV_DEBUG=ON -DDEV_WITH_TYSAN=ON -DWITH_LTO=OFF -DWITH_INDEXED_HASHES=ON -DCMAKE_POLICY_VERSION_MINIMUM="3.5"
make -j$(nproc) p2pool
- name: Run p2pool
run: |
cd build
mkdir data
python ../tests/src/stratum_dummy.py 1 &
python ../tests/src/stratum_dummy.py 2 &
python ../tests/src/stratum_dummy.py 3 &
sudo sysctl vm.mmap_rnd_bits=28
TYSAN_OPTIONS=print_stacktrace=1 ./p2pool --host node.monerodevs.org --rpc-port 18089 --zmq-port 18084 --host node.richfowler.net --rpc-port 18089 --zmq-port 18084 --rpc-ssl --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg ${{ secrets.MM_PARAMS }} --out-peers 50 --data-api data --local-api --loglevel 6 --light-mode 2> stderr.log
- name: Check synchronization
run: |
cd build
grep 'Synchronization finished successfully' p2pool.log
- name: Check p2pool.log for errors
run: |
cd build
../scripts/workflows/test-sync-check.sh
- name: Archive p2pool.log
if: '!cancelled()'
uses: actions/upload-artifact@v4
with:
name: p2pool_ubuntu_data_tysan
path: |
build/*.log
build/data/
sync-test-macos:
timeout-minutes: 120
+1
View File
@@ -27,6 +27,7 @@ option(DEV_WITH_TSAN "[Developer only] Compile with thread sanitizer" OFF)
option(DEV_WITH_MSAN "[Developer only] Compile with memory sanitizer" OFF)
option(DEV_WITH_UBSAN "[Developer only] Compile with undefined behavior sanitizer" OFF)
option(DEV_WITH_ASAN "[Developer only] Compile with address sanitizer" OFF)
option(DEV_WITH_TYSAN "[Developer only] Compile with type sanitizer" OFF)
option(DEV_CLANG_TIDY "[Developer only] Compile for clang-tidy" OFF)
option(DEV_TRACK_MEMORY "[Developer only] Track memory allocations" OFF)
option(DEV_DEBUG "[Developer only] Compile a debug build" OFF)
+18 -5
View File
@@ -2,7 +2,13 @@
Decentralized pool for Monero mining.
Pool status and monitoring pages can be found at https://p2pool.io/, https://p2pool.io/mini/ and https://p2pool.observer/, https://mini.p2pool.observer/
Pool status and monitoring pages can be found at:
|P2Pool||
|-|-|
|main|https://p2pool.io/ <br> https://p2pool.observer/|
|mini|https://p2pool.io/mini/ <br> https://mini.p2pool.observer/|
|nano|https://p2pool.io/nano/ <br> https://nano.p2pool.observer/|
These are 3rd-party pages. If they are down, it doesn't mean there is a problem with P2Pool itself - it keeps mining always thanks to its decentralized nature.
@@ -92,8 +98,15 @@ In order to continue mining on P2Pool, you must update both Monero and P2Pool so
- In order to mine on P2Pool, a synced Monero node using monerod v0.18.0.0 or newer is required. If you don't currently have one, you can download the [official Monero binaries](https://www.getmonero.org/downloads/), start `monerod` on your PC and wait until it's fully synced. Advanced Monero node setup instructions are [here](https://sethforprivacy.com/guides/run-a-monero-node-advanced/).
- It is highly recommended that you create a separate restricted user account (in your OS) for mining. While P2Pool has been battle-tested for a long time now, any software may have unknown bugs/vulnerabilities.
- You can mine to a primary wallet address (the one starting with `4`) for mining. If you want to mine to a subaddress, you will need to provide both the main address (starting with 4) and the subaddress (starting with 8) using `--wallet` and `--subaddress` command line parameters.
- You can add the `--mini` parameter to your P2Pool command to connect to the **p2pool-mini** sidechain. Note that it will also change the default p2p port from 37889 to 37888.
- Check that ports 18080 (Monero p2p port) and 37889/37888 (P2Pool/P2Pool mini 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 add the `--mini` or `--nano` parameter to your P2Pool command to connect to the respective sidechain.
> [!NOTE]
>
> You cannot use both `--mini` and `--nano` together
>
> Using `--mini` will change the p2p port to 37888.
>
> Using `--nano` will change the p2p port to 37890.
- Check that ports 18080 (Monero p2p port) and 37889/37888/37890 (P2Pool default/mini/nano p2p port) are open in your firewall to ensure better connectivity. If you're mining from a computer behind NAT (like a router) you could consider forwarding the ports to your local machine.
- You can connect multiple miners to the same P2Pool node. The more the better!
- The steps below assume that you run everything on the same machine. If it's not the case, change `127.0.0.1` to appropriate IP addresses for your setup.
- It is highly recommended to create a new mainnet wallet for P2Pool mining because **wallet addresses are public on P2Pool**.
@@ -108,7 +121,7 @@ In order to continue mining on P2Pool, you must update both Monero and P2Pool so
### GUI for P2Pool
- [Gupax](https://github.com/hinto-janai/gupax) project aims to provide an easy to use cross-platform GUI to configure and run P2Pool & [XMRig](https://github.com/xmrig/xmrig).
- [Gupax](https://github.com/gupax-io/gupax) project aims to provide an easy to use cross-platform GUI to configure and run P2Pool & [XMRig](https://github.com/xmrig/xmrig).
### Merge mining
@@ -152,7 +165,7 @@ Note that Tari will be mined in solo mode (only full Tari blocks can be mined fo
```
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.
4. Check that ports 18080 (Monero p2p port) and 37889/37888/37890 (P2Pool default/mini/nano 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 --enforce-dns-checkpointing --enable-dns-blocklist
+5 -1
View File
@@ -113,6 +113,10 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(GENERAL_FLAGS "${GENERAL_FLAGS} -mfix-cortex-a53-835769")
endif()
if (DEV_WITH_TYSAN)
set(GENERAL_FLAGS "${GENERAL_FLAGS} -fno-omit-frame-pointer -fsanitize=type")
endif()
set(WARNING_FLAGS "-Wall -Wextra -Wno-unused-function -Wno-undefined-internal -Wno-unknown-warning-option -Wno-nan-infinity-disabled -Wunreachable-code-aggressive -Wmissing-prototypes -Wmissing-variable-declarations -Werror")
if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20))
@@ -123,7 +127,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(WARNING_FLAGS "-w")
endif()
if (DEV_WITH_MSAN OR DEV_DEBUG OR (CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
if (DEV_WITH_MSAN OR DEV_WITH_TYSAN OR DEV_DEBUG OR (CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
add_definitions(-DDEBUG_BUILD)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(OPTIMIZATION_FLAGS "-O0")
+4 -4
View File
@@ -3,7 +3,7 @@ set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER /usr/local/bin/aarch64-apple-darwin25-clang)
set(CMAKE_CXX_COMPILER /usr/local/bin/aarch64-apple-darwin25-clang++)
set(CMAKE_ASM_COMPILER /usr/local/bin/aarch64-apple-darwin25-as)
set(CMAKE_STRIP /usr/local/bin/aarch64-apple-darwin25-strip)
set(CMAKE_C_COMPILER /usr/local/bin/aarch64-apple-darwin25.1-clang)
set(CMAKE_CXX_COMPILER /usr/local/bin/aarch64-apple-darwin25.1-clang++)
set(CMAKE_ASM_COMPILER /usr/local/bin/aarch64-apple-darwin25.1-as)
set(CMAKE_STRIP /usr/local/bin/aarch64-apple-darwin25.1-strip)
+4 -4
View File
@@ -3,7 +3,7 @@ set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER /usr/local/bin/x86_64-apple-darwin25-clang)
set(CMAKE_CXX_COMPILER /usr/local/bin/x86_64-apple-darwin25-clang++)
set(CMAKE_ASM_COMPILER /usr/local/bin/x86_64-apple-darwin25-as)
set(CMAKE_STRIP /usr/local/bin/x86_64-apple-darwin25-strip)
set(CMAKE_C_COMPILER /usr/local/bin/x86_64-apple-darwin25.1-clang)
set(CMAKE_CXX_COMPILER /usr/local/bin/x86_64-apple-darwin25.1-clang++)
set(CMAKE_ASM_COMPILER /usr/local/bin/x86_64-apple-darwin25.1-as)
set(CMAKE_STRIP /usr/local/bin/x86_64-apple-darwin25.1-strip)
+2 -1
View File
@@ -33,7 +33,7 @@ docker compose up
```
#### Optional
* Open ports 18080 (Monero p2p port) and 37889 (P2Pool p2p port) or 37888 (P2Pool-mini 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
* Open ports 18080 (Monero p2p port) and 37889/37888/37890 (P2Pool default/mini/nano 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 (or alternate if configured) when you set it as "exposed" in the configuration
* Configure your kernel for maximum mining performance: [XMRig RandomX Optimization Guide](https://xmrig.com/docs/miner/randomx-optimization-guide)
* Many optional configurations and customizations are available by running './configure'
@@ -54,4 +54,5 @@ Change to p2pool/docker-compose directory <br />
Stop and remove all containers: ```docker compose down``` <br />
Remove the p2pool data: ```docker volume rm p2pool``` <br />
Remove the p2pool-mini data: ```docker volume rm p2pool-mini``` <br />
Remove the p2pool-nano data: ```docker volume rm p2pool-nano``` <br />
Remove the monero data: ```docker volume rm monero```
+3 -2
View File
@@ -37,7 +37,8 @@ class P2PoolHelpBox(HelpBoxBase):
"P2Pool Sidechain:": [
"Which P2Pool sidechain to mine on",
" use main for faster miners",
" use mini for slower miners",
" use mini for slow miners (>30kH/s)",
" use nano for slower miners (<30kH/s)",
],
"Enable Server Statistics": [
"Provide access to your P2Pool server statictics via a web interface",
@@ -364,7 +365,7 @@ class P2PoolConfigForm(ConfigFormBase):
self.sidechain = self.add(
npyscreen.TitleSelectOne,
name="P2Pool Sidechain:",
values=["main", "mini"],
values=["main", "mini", "nano"],
scroll_exit=True,
max_height=2,
value=[
+7 -3
View File
@@ -7,10 +7,12 @@ networks:
volumes:
p2pool:
{% if sidechain[0] == 0 %}
name: p2pool
{% else %}
{% if sidechain[0] == 1 %}
name: p2pool-mini
{% elif sidechain[0] == 2 %}
name: p2pool-nano
{% else %}
name: p2pool
{% endif %}
{% if configure_monero == True %}
@@ -55,6 +57,8 @@ services:
--loglevel {{ p2pool_log_level | int }}
{% if sidechain[0] == 1 %}
--mini
{% elif sidechain[0] == 2 %}
--nano
{% endif %}
{% if enable_autodiff == False %}
--no-autodiff
+20 -2
View File
@@ -13,6 +13,7 @@
--light-mode Don't allocate RandomX dataset, saves 2GB of RAM
--loglevel Verbosity of the log, integer number between 0 and 6
--data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory
--log-file Path to the log file, default is "p2pool.log" in p2pool's working directory
--sidechain-config Name of the p2pool sidechain parameters file (only use it if you run your own sidechain)
--data-api Path to the p2pool JSON data (use it in tandem with an external web-server). Not affected by --data-dir setting!
--local-api Enable /local/ path in api path for Stratum Server and built-in miner statistics
@@ -23,8 +24,8 @@
--out-peers N Maximum number of outgoing connections for p2p server (any value between 10 and 450)
--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 450)
--start-mining N Start built-in miner using N threads (any value between 1 and 64)
--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from 37889 to 37888
--nano Connect to p2pool-nano sidechain. Note that it will also change default p2p port from 37889 to 37890
--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from 37889 to 37888. Cannot be used with --nano.
--nano Connect to p2pool-nano sidechain. Note that it will also change default p2p port from 37889 to 37890. Cannot be used with --mini.
--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)
--rpc-login Specify username[:password] required for Monero RPC server
--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections
@@ -43,6 +44,7 @@
--full-validation Enables full share validation / increases CPU usage
--onion-address Tell other peers to use this .onion address to connect to this node through TOR
--no-clearnet-p2p Forces P2P server to listen on 127.0.0.1 and to not connect to clearnet IPs
--params-file File name to load parameters from. It can't be used together with any other command line parameters
```
### Example command line
@@ -51,6 +53,22 @@
p2pool.exe --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:3333 --p2p 0.0.0.0:37889
```
### Example command line (params file)
```
p2pool.exe --params-file params.conf
```
params.conf
```
# IP of your node
host = 127.0.0.1
wallet = YOUR_WALLET_ADDRESS
data-api = "/path/to/api/folder" # use quotes if you have spaces in the path
loglevel = 4
mini = 1
```
### Example command line (mining to a subaddress)
```
+3 -2
View File
@@ -256,7 +256,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<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>37888</span> (P2Pool mini port) in your firewall to ensure better connectivity
<li>[Optional] Open port <span>37889</span> (P2Pool p2p port) in your firewall to ensure better connectivity
<li>Run <span>./p2pool --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS</span>
<li>It should take no more than 5-10 minutes to synchronize
</ul></details>
@@ -274,6 +274,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<ul>
<li>You can enter your wallet address at <a href="https://p2pool.observer/" target="_blank">P2Pool Observer</a>
<li>P2Pool Observer for P2Pool mini can be found <a href="https://mini.p2pool.observer/" target="_blank">here</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>
@@ -300,7 +301,7 @@ P2Pool is a decentralized community, there is no dedicated support. You can reac
<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://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 by adding <span style="color:#808080;">--mini</span> to P2Pool command line.</ul><br>
<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 either P2Pool mini or 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>
+3 -2
View File
@@ -256,7 +256,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<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>37888</span> (P2Pool mini port) in your firewall to ensure better connectivity
<li>[Optional] Open port <span>37888</span> (P2Pool mini p2p port) in your firewall to ensure better connectivity
<li>Run <span>./p2pool --host 127.0.0.1 --wallet YOUR_WALLET_ADDRESS --mini</span>
<li>It should take no more than 5-10 minutes to synchronize
</ul></details>
@@ -274,6 +274,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<ul>
<li>You can enter your wallet address at <a href="https://p2pool.observer/" target="_blank">P2Pool Observer</a>
<li>P2Pool Observer for P2Pool mini can be found <a href="https://mini.p2pool.observer/" target="_blank">here</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>
@@ -300,7 +301,7 @@ P2Pool is a decentralized community, there is no dedicated support. You can reac
<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://mini.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 by adding <span style="color:#808080;">--mini</span> to P2Pool command line.</ul><br>
<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 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>
+2 -1
View File
@@ -259,7 +259,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<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>[Optional] Open port <span>37890</span> (P2Pool nano p2p 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>
@@ -276,6 +276,7 @@ It's highly recommended to create a new wallet for mining because wallet address
<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 mini can be found <a href="https://mini.p2pool.observer/" target="_blank">here</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>
+9 -11
View File
@@ -1,5 +1,5 @@
diff --git a/crypto/rand/windows.cc b/crypto/rand/windows.cc
index 59df467e7..aa5ac076c 100644
index 6a93a2d84..f75112b4f 100644
--- a/crypto/rand/windows.cc
+++ b/crypto/rand/windows.cc
@@ -24,6 +24,7 @@
@@ -10,10 +10,10 @@ index 59df467e7..aa5ac076c 100644
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@@ -57,16 +58,40 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
@@ -57,16 +58,39 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
typedef BOOL (WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData);
static ProcessPrngFunction g_processprng_fn = NULL;
static ProcessPrngFunction g_processprng_fn = nullptr;
+static HCRYPTPROV g_hCryptProv = 0;
+
+static BOOL WINAPI wrapper_CryptGenRandom(PBYTE pbData, SIZE_T cbData)
@@ -23,19 +23,17 @@ index 59df467e7..aa5ac076c 100644
static void init_processprng(void) {
HMODULE hmod = LoadLibraryW(L"bcryptprimitives");
- if (hmod == NULL) {
- if (hmod == nullptr) {
- abort();
- }
- g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng");
- if (g_processprng_fn == NULL) {
- abort();
+
+ if (hmod) {
+ g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng");
+ if (g_processprng_fn) {
+ return;
+ }
+ }
}
- g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng");
- if (g_processprng_fn == nullptr) {
- abort();
+
+ if (CryptAcquireContext(&g_hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
+ g_processprng_fn = &wrapper_CryptGenRandom;
@@ -51,7 +49,7 @@ index 59df467e7..aa5ac076c 100644
+ else {
+ err = GetLastError();
+ }
+ }
+ }
+
+ abort();
}
+11 -11
View File
@@ -4,27 +4,27 @@ set -e
# Software versions to install
_7ZIP_VERSION=2501
BINUTILS_VERSION=2_45
CLANG_VERSION=21.1.5
CMAKE_VERSION=4.1.2
BINUTILS_VERSION=2_45_1
CLANG_VERSION=21.1.8
CMAKE_VERSION=4.2.1
FREEBSD_VERSION=12.4
GCC_VERSION=15.2.0
GLIBC_VERSION=2.42
LINUX_HEADERS_VERSION=6.17.7
MACOSX_SDK_VERSION=26.0
OSXCROSS_VERSION=7e8a4d170cc6bda1f0a32f5dc5f6ace4676baf98
LINUX_HEADERS_VERSION=6.18.1
MACOSX_SDK_VERSION=26.1
OSXCROSS_VERSION=2bc739ebe45db5d72e176d2a4e1c7dd95464e8e2
MAKE_VERSION=4.4.1
MINGW_VERSION=13.0.0
XZ_VERSION=5.8.1
XZ_VERSION=5.8.2
TAR_VERSION=1.35
_7ZIP_SHA256="4ca3b7c6f2f67866b92622818b58233dc70367be2f36b498eb0bdeaaa44b53f4"
CMAKE_SHA256="773cc679c3a7395413bd096523f8e5d6c39f8718af4e12eb4e4195f72f35e4ab"
CMAKE_SHA256="c059bff1e97a2b6b5b0c0872263627486345ad0ed083298cb21cff2eda883980"
FREEBSD_AARCH64_SHA256="6c401819bfb93e810c9f9aa670a1e4685f924df5e7e0c9c6397dd6c16c954fa2"
FREEBSD_X86_64_SHA256="581c7edacfd2fca2bdf5791f667402d22fccd8a5e184635e0cac075564d57aa8"
GLIBC_SHA256="d1775e32e4628e64ef930f435b67bb63af7599acb6be2b335b9f19f16509f17f"
HEADERS_SHA256="ddf2ea0d4439e1d57136be3623102af9458f601f5b1cb77e83246e88aea09d0e"
MACOSX_SDK_SHA256="07ccaa2891454713c3a230dd87283f76124193309d9a7617ebee45354c9302d2"
HEADERS_SHA256="d0a78bf3f0d12aaa10af3b5adcaed5bc767b5b78705e5ef885d5e930b72e25d5"
MACOSX_SDK_SHA256="beee7212d265a6d2867d0236cc069314b38d5fb3486a6515734e76fa210c784c"
MAKE_SHA256="dd16fb1d67bfab79a72f5e8390735c49e3e8e70b4945a15ab1f81ddb78658fb3"
TAR_SHA256="4d62ff37342ec7aed748535323930c7cf94acf71c3591882b26a7ea50f3edc16"
@@ -227,7 +227,7 @@ cd /root
tar xvf $CMAKE_FILE
cp $CMAKE_NAME/bin/* /usr/local/bin
cp -r $CMAKE_NAME/share/cmake-4.1 /usr/local/share
cp -r $CMAKE_NAME/share/cmake-4.2 /usr/local/share
echo "Install clang"
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
grep 'ERROR ' p2pool.log | grep -E -v 'submit_block|failed to bind|ZMQ is not running|block header for seed' > errors.log
grep 'ERROR ' p2pool.log | grep -E -v 'submit_block|failed to bind|ZMQ is not running|block header for seed|ZMQReader|ZMQ reader|uv_poll_start returned error EBADF' > errors.log
if [ -s errors.log ]; then
cat errors.log
+3
View File
@@ -4,6 +4,9 @@
//
// Fixed difficulty for miners that connect to your node must be set in their config.json
//
// Note: nano sidechain uses
// "block_time": 30
// "uncle_penalty": 10
{
"name": "default",
"password": "",
+7 -6
View File
@@ -20,6 +20,7 @@
#include "pool_block.h"
#include "p2p_server.h"
#include "side_chain.h"
#include "params.h"
LOG_CATEGORY(BlockCache)
@@ -34,9 +35,9 @@ struct BlockCache::Impl : public nocopy_nomove
{
#if defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) || defined(__MACH__)
Impl()
explicit Impl(const Params& params)
{
const std::string cache_path = DATA_DIR + cache_name;
const std::string cache_path = params.m_dataDir + cache_name;
m_fd = open(cache_path.c_str(), O_RDWR | O_CREAT, static_cast<mode_t>(0600));
if (m_fd == -1) {
@@ -88,8 +89,8 @@ struct BlockCache::Impl : public nocopy_nomove
#elif defined(_WIN32)
Impl()
: m_cachePath(DATA_DIR + cache_name)
explicit Impl(const Params& params)
: m_cachePath(params.m_dataDir + cache_name)
, m_file(CreateFile(m_cachePath.c_str(), GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL))
, m_map(0)
{
@@ -157,8 +158,8 @@ struct BlockCache::Impl : public nocopy_nomove
uint8_t* m_data = nullptr;
};
BlockCache::BlockCache()
: m_impl(new Impl())
BlockCache::BlockCache(const Params& params)
: m_impl(new Impl(params))
, m_flushRunning(0)
, m_storeIndex(0)
, m_loadingStarted(0)
+2 -1
View File
@@ -22,11 +22,12 @@ namespace p2pool {
struct PoolBlock;
class SideChain;
class P2PServer;
struct Params;
class BlockCache : public nocopy_nomove
{
public:
BlockCache();
explicit BlockCache(const Params& params);
~BlockCache();
void store(const PoolBlock& block);
+7 -7
View File
@@ -204,7 +204,7 @@ void BlockTemplate::shuffle_tx_order()
}
}
void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const Params* params)
void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const Params& params)
{
if (data.major_version > HARDFORK_SUPPORTED_VERSION) {
LOGERR(1, "got hardfork version " << data.major_version << ", expected <= " << HARDFORK_SUPPORTED_VERSION);
@@ -269,7 +269,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
m_blockHeaderSize = m_blockHeader.size();
m_poolBlockTemplate->m_minerWallet = params->m_miningWallet;
m_poolBlockTemplate->m_minerWallet = params.m_miningWallet;
if (!m_sidechain->fill_sidechain_data(*m_poolBlockTemplate, m_shares)) {
use_old_template();
@@ -595,7 +595,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
m_poolBlockTemplate->m_transactions.push_back(m_mempoolTxs[m_mempoolTxsOrder[i]].id);
}
m_poolBlockTemplate->m_minerWallet = params->m_miningWallet;
m_poolBlockTemplate->m_minerWallet = params.m_miningWallet;
// Layout: [software id, version, random number, sidechain extra_nonce]
uint32_t* sidechain_extra = m_poolBlockTemplate->m_sidechainExtraBuf;
@@ -630,16 +630,16 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
m_poolBlockTemplate->m_mergeMiningExtra.emplace(c.unique_id, std::move(v));
}
if (params->m_subaddress.valid()) {
if (params.m_subaddress.valid()) {
uint8_t buf[HASH_SIZE + 2] = {};
memcpy(buf, params->m_subaddress.view_public_key().h, HASH_SIZE);
memcpy(buf, params.m_subaddress.view_public_key().h, HASH_SIZE);
m_poolBlockTemplate->m_mergeMiningExtra.emplace(keccak_subaddress_viewpub, std::vector(buf, buf + sizeof(buf)));
}
if (!params->m_onionPubkey.empty()) {
if (!params.m_onionPubkey.empty()) {
uint8_t buf[HASH_SIZE + 2] = {};
memcpy(buf, params->m_onionPubkey.h, HASH_SIZE);
memcpy(buf, params.m_onionPubkey.h, HASH_SIZE);
m_poolBlockTemplate->m_mergeMiningExtra.emplace(keccak_onion_address_v3, std::vector(buf, buf + sizeof(buf)));
}
+1 -1
View File
@@ -40,7 +40,7 @@ public:
BlockTemplate(const BlockTemplate& b);
BlockTemplate& operator=(const BlockTemplate& b);
void update(const MinerData& data, const Mempool& mempool, const Params* params);
void update(const MinerData& data, const Mempool& mempool, const Params& params);
uint64_t last_updated() const { return m_lastUpdated.load(); }
bool get_difficulties(const uint32_t template_id, uint64_t& height, uint64_t& sidechain_height, difficulty_type& mainchain_difficulty, difficulty_type& aux_diff, difficulty_type& sidechain_difficulty) const;
+13 -5
View File
@@ -18,6 +18,7 @@
#include "common.h"
#include "uv_util.h"
#include "wallet.h"
#include "params.h"
#include <ctime>
#include <fstream>
#include <thread>
@@ -118,7 +119,7 @@ public:
BUF_SIZE = SLOT_SIZE * 8192,
};
FORCEINLINE Worker()
FORCEINLINE explicit Worker(const Params& p)
: m_writePos(0)
, m_readPos(0)
, m_stopped(false)
@@ -132,7 +133,7 @@ public:
std::setlocale(LC_ALL, "en_001");
m_logFilePath = DATA_DIR + log_file_name;
m_logFilePath = p.m_logFilePath.empty() ? (p.m_dataDir + log_file_name) : p.m_logFilePath;
m_buf.resize(BUF_SIZE);
@@ -478,16 +479,23 @@ NOINLINE Writer::~Writer()
m_buf[2] = static_cast<char>(static_cast<uint8_t>(size >> 8));
m_buf[m_pos] = '\n';
#ifndef P2POOL_LOG_DISABLE
worker->write(m_buf, size);
if (worker) {
worker->write(m_buf, size);
}
else {
fwrite(m_buf + 3, 1, size - 3, (m_buf[0] == 1) ? stdout : stderr);
}
#endif
}
void start()
void start(const Params& p)
{
#ifndef P2POOL_LOG_DISABLE
worker = new Worker();
worker = new Worker(p);
LOGINFO(0, "started");
#else
(void)p;
#endif
}
+2 -1
View File
@@ -20,6 +20,7 @@
namespace p2pool {
class Wallet;
struct Params;
namespace log {
@@ -622,7 +623,7 @@ struct DummyStream
#endif
void start();
void start(const Params& p);
void reopen();
void stop();
+80 -51
View File
@@ -38,7 +38,6 @@
#endif // WITH_GRPC
#include <filesystem>
#include <fstream>
#ifdef WITH_RANDOMX
#include "randomx.h"
@@ -72,6 +71,7 @@ void p2pool_usage()
"--light-mode Don't allocate RandomX dataset, saves 2GB of RAM\n"
"--loglevel Verbosity of the log, integer number between 0 and %d\n"
"--data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory\n"
"--log-file Path to the log file, default is \"p2pool.log\" in p2pool's working directory\n"
"--sidechain-config Name of the p2pool sidechain parameters file (only use it if you run your own sidechain)\n"
"--data-api Path to the p2pool JSON data (use it in tandem with an external web-server). Not affected by --data-dir setting!\n"
"--local-api Enable /local/ path in api path for Stratum Server and built-in miner statistics\n"
@@ -108,6 +108,7 @@ void p2pool_usage()
"--full-validation Enables full share validation / increases CPU usage\n"
"--onion-address Tell other peers to use this .onion address to connect to this node through TOR\n"
"--no-clearnet-p2p Forces P2P server to listen on 127.0.0.1 and to not connect to clearnet IPs\n"
"--params-file File name to load parameters from. It can't be used together with any other command line parameters\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",
@@ -222,6 +223,56 @@ int p2pool_test()
return 0;
}
static p2pool::Params get_params(int argc, const char* const argv[]) noexcept
{
try {
std::vector<std::vector<std::string>> args;
args.reserve(argc);
// Group command-line parameters by the pattern "--name [data1 data2 ... data_n]"
// Each parameter starting with "--" can have 0 or more values attached to it
for (int i = 1; i < argc; ++i) {
std::string_view arg = argv[i];
if ((arg.size() > 2) && (arg[0] == '-') && (arg[1] == '-')) {
// Store the parameter name without the "--" prefix
arg.remove_prefix(2);
args.emplace_back(1, std::string(arg));
}
else if (!args.empty()) {
args.back().emplace_back(std::move(arg));
}
}
p2pool::Params params(args);
if (params.valid()) {
return params;
}
}
catch (const std::exception&) {
}
printf("Invalid or missing command line. Try \"p2pool --help\".\n");
abort();
}
static p2pool::Params get_params(const std::string& params_file) noexcept
{
try {
p2pool::Params params(p2pool::parse_config(params_file));
if (params.valid()) {
return params;
}
}
catch (const std::exception&) {
}
printf("Invalid or missing command line. Try \"p2pool --help\".\n");
abort();
}
int main(int argc, char* argv[])
{
if (argc == 1) {
@@ -229,11 +280,10 @@ int main(int argc, char* argv[])
return 0;
}
bool is_mini = false;
bool is_nano = false;
std::string params_file;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "/help") || !strcmp(argv[i], "-h") || !strcmp(argv[i], "/h")) {
if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "/help") || !strcmp(argv[i], "-h") || !strcmp(argv[i], "/h") || !strcmp(argv[i], "/?")) {
p2pool_usage();
return 0;
}
@@ -247,52 +297,14 @@ int main(int argc, char* argv[])
return p2pool_test();
}
if ((strcmp(argv[i], "--data-dir") == 0) && (i + 1 < argc)) {
std::string path = argv[++i];
p2pool::DATA_DIR = std::move(path);
p2pool::fixup_path(p2pool::DATA_DIR);
}
if (!strcmp(argv[i], "--mini")) is_mini = true;
if (!strcmp(argv[i], "--nano")) is_nano = true;
}
// If the data directory is not set, check if P2Pool has write access to the current directory
// If it doesn't, switch to user's home directory
if (p2pool::DATA_DIR.empty()) {
std::ofstream f("p2pool.tmp");
if (f && f.put(' ')) {
f.close();
std::remove("p2pool.tmp");
}
else {
char buf[1024];
size_t size = sizeof(buf);
if (uv_os_homedir(buf, &size) == 0) {
p2pool::DATA_DIR.assign(buf, size);
p2pool::fixup_path(p2pool::DATA_DIR);
p2pool::DATA_DIR += ".p2pool/";
if (is_mini) {
p2pool::DATA_DIR += "mini/";
}
else if (is_nano) {
p2pool::DATA_DIR += "nano/";
}
}
if (!strcmp(argv[i], "--params-file") && (i + 1 < argc)) {
params_file = argv[++i];
}
}
if (!p2pool::DATA_DIR.empty()) {
printf("Using \"%s\" for P2Pool files\n", p2pool::DATA_DIR.c_str());
}
// Try to create it if it doesn't exist
if (!p2pool::DATA_DIR.empty()) {
std::error_code err;
std::filesystem::create_directories(p2pool::DATA_DIR, err);
if (!params_file.empty() && (argc != 3)) {
fprintf(stderr, "--params-file can't be combined with other command line parameters\n");
return 1;
}
#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG)
@@ -303,14 +315,29 @@ int main(int argc, char* argv[])
memory_tracking_start();
// Create default loop here
int result;
{
// Create the default libuv loop and initialize libuv here
// It will call the important stuff like WSAStartup and many other things
// Some P2Pool code will not work without libuv initialized, so the code above this line must be minimal
uv_default_loop();
p2pool::log::start();
const p2pool::Params params = params_file.empty() ? get_params(argc, argv) : get_params(params_file);
if (!params.m_dataDir.empty()) {
printf("Using \"%s\" for P2Pool files\n", params.m_dataDir.c_str());
// Try to create it if it doesn't exist
std::error_code err;
std::filesystem::create_directories(params.m_dataDir, err);
}
p2pool::log::start(params);
p2pool::init_crypto_cache();
int result = static_cast<int>(curl_global_init_mem(CURL_GLOBAL_ALL, p2pool::malloc_hook, p2pool::free_hook, p2pool::realloc_hook, p2pool::strdup_hook, p2pool::calloc_hook));
result = static_cast<int>(curl_global_init_mem(CURL_GLOBAL_ALL, p2pool::malloc_hook, p2pool::free_hook, p2pool::realloc_hook, p2pool::strdup_hook, p2pool::calloc_hook));
if (result != CURLE_OK) {
return result;
}
@@ -327,7 +354,7 @@ int main(int argc, char* argv[])
#endif
try {
p2pool::p2pool pool(argc, argv);
p2pool::p2pool pool(params);
result = pool.run();
}
catch (...) {
@@ -354,6 +381,8 @@ int main(int argc, char* argv[])
uv_library_shutdown();
#endif
}
if (!memory_tracking_stop()) {
result = 1;
}
+13 -10
View File
@@ -48,9 +48,9 @@ LOG_CATEGORY(P2PServer)
static constexpr char saved_peer_list_file_name[] = "p2pool_peers.txt";
static constexpr char saved_onion_peer_list_file_name[] = "p2pool_onion_peers.txt";
static const char* seed_nodes[] = { "seeds.p2pool.io", "main.p2poolpeers.net", "main.gupax.io", "" };
static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "mini.p2poolpeers.net", "mini.gupax.io", "" };
static const char* seed_nodes_nano[] = { "seeds-nano.p2pool.io", "nano.p2poolpeers.net", "nano.gupax.io", ""};
static const char* seed_nodes[] = { "seeds.p2pool.io", "main.p2poolpeers.net", "" };
static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "mini.p2poolpeers.net", "" };
static const char* seed_nodes_nano[] = { "seeds-nano.p2pool.io", "nano.p2poolpeers.net", ""};
static constexpr int DEFAULT_BACKLOG = 16;
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
@@ -66,7 +66,7 @@ static constexpr hash seed_onion_nodes[] = {
P2PServer::P2PServer(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, P2PClient::allocate, pool->params().m_socks5Proxy)
, m_pool(pool)
, m_cache(pool->params().m_blockCache ? new BlockCache() : nullptr)
, m_cache(pool->params().m_blockCache ? new BlockCache(pool->params()) : nullptr)
, m_cacheLoaded(false)
, m_initialPeerList(pool->params().m_p2pPeerList)
, m_cachedBlocks(nullptr)
@@ -561,7 +561,9 @@ void P2PServer::save_peer_list_async()
void P2PServer::save_peer_list()
{
const std::string path = DATA_DIR + saved_peer_list_file_name;
const Params& params = m_pool->params();
const std::string path = params.m_dataDir + saved_peer_list_file_name;
std::ofstream f(path, std::ios::binary);
@@ -606,7 +608,7 @@ void P2PServer::save_peer_list()
const SideChain& s = m_pool->side_chain();
if (s.onion_pubkeys_count() > 0) {
const std::string onion_path = DATA_DIR + saved_onion_peer_list_file_name;
const std::string onion_path = params.m_dataDir + saved_onion_peer_list_file_name;
f.open(onion_path, std::ios::binary);
@@ -726,7 +728,7 @@ void P2PServer::load_peer_list()
// Finally load peers from p2pool_peers.txt and p2pool_onion_peers.txt
for (size_t i = 0, n = (m_socks5Proxy.empty() ? 1 : 2); i < n; ++i) {
const std::string path = DATA_DIR + (i ? saved_onion_peer_list_file_name : saved_peer_list_file_name);
const std::string path = m_pool->params().m_dataDir + (i ? saved_onion_peer_list_file_name : saved_peer_list_file_name);
std::ifstream f(path);
@@ -1295,11 +1297,12 @@ void P2PServer::on_timer()
return;
}
++m_timerCounter;
const uint64_t t = ++m_timerCounter;
if (!m_initialPeerList.empty()) {
if ((t == 1) && !m_initialPeerList.empty()) {
connect_to_peers(m_initialPeerList);
m_initialPeerList.clear();
return;
}
flush_cache();
@@ -1892,7 +1895,7 @@ void P2PServer::P2PClient::reset()
if (server->m_fastestPeer == this) {
server->m_fastestPeer = nullptr;
}
if (m_addressType == AddressType::DomainName) {
if ((m_addressType == AddressType::DomainName) && m_connectedTime) {
--server->m_numOnionConnections;
}
}
+46 -79
View File
@@ -63,8 +63,9 @@ namespace p2pool {
static uint64_t BLOCK_HEADERS_REQUIRED = 720;
p2pool::p2pool(int argc, char* argv[])
p2pool::p2pool(const Params& params)
: m_stopped(false)
, m_params(params)
, m_updateSeed(true)
, m_submitBlockData{}
, m_zmqLastActive(0)
@@ -73,49 +74,33 @@ p2pool::p2pool(int argc, char* argv[])
{
LOGINFO(1, log::LightCyan() << VERSION);
Params* p = new Params(argc, argv);
if (!p->valid()) {
LOGERR(1, "Invalid or missing command line. Try \"p2pool --help\".");
delete p;
throw std::exception();
}
m_params = p;
// P2Pool-nano requires more Monero blocks for the initial sync
if (m_params->m_nano) {
if (m_params.m_nano) {
BLOCK_HEADERS_REQUIRED = 1440;
}
bkg_jobs_tracker = new BackgroundJobTracker();
#ifdef WITH_UPNP
if (p->m_upnp) {
if (m_params.m_upnp) {
init_upnp();
}
#endif
for (Params::Host& h : p->m_hosts) {
if (!h.init_display_name(*p)) {
throw std::exception();
}
}
m_currentHostIndex = 0;
m_hostPing.resize(p->m_hosts.size());
m_hostPing.resize(m_params.m_hosts.size());
hash pub, sec, eph_public_key;
generate_keys(pub, sec);
uint8_t view_tag;
if (!p->m_miningWallet.get_eph_public_key(sec, 0, eph_public_key, view_tag)) {
if (!m_params.m_miningWallet.get_eph_public_key(sec, 0, eph_public_key, view_tag)) {
LOGERR(1, "Invalid wallet address: get_eph_public_key failed");
throw std::exception();
}
const NetworkType type = p->m_miningWallet.type();
const NetworkType type = m_params.m_miningWallet.type();
if (type == NetworkType::Testnet) {
LOGWARN(1, "Mining to a testnet wallet address");
@@ -196,34 +181,17 @@ p2pool::p2pool(int argc, char* argv[])
}
m_timer.data = this;
m_api = p->m_apiPath.empty() ? nullptr : new p2pool_api(p->m_apiPath, p->m_localStats);
m_api = m_params.m_apiPath.empty() ? nullptr : new p2pool_api(m_params.m_apiPath, m_params.m_localStats);
if (p->m_localStats && !m_api) {
if (m_params.m_localStats && !m_api) {
LOGERR(1, "--local-api and --stratum-api command line parameters can't be used without --data-api");
throw std::exception();
}
m_sideChain = new SideChain(this, type, p->m_mini ? "mini" : (p->m_nano ? "nano" : nullptr));
const int p2p_port = m_sideChain->is_mini() ? DEFAULT_P2P_PORT_MINI : (m_sideChain->is_nano() ? DEFAULT_P2P_PORT_NANO : DEFAULT_P2P_PORT);
if (p->m_noClearnetP2P) {
char buf[48] = {};
log::Stream s(buf);
s << "127.0.0.1:" << p2p_port;
p->m_p2pAddresses = buf;
}
else if (p->m_p2pAddresses.empty()) {
char buf[48] = {};
log::Stream s(buf);
s << "[::]:" << p2p_port << ",0.0.0.0:" << p2p_port;
p->m_p2pAddresses = buf;
}
m_sideChain = new SideChain(this, type, m_params.m_mini ? "mini" : (m_params.m_nano ? "nano" : nullptr));
#ifdef WITH_RANDOMX
if (p->m_disableRandomX) {
if (m_params.m_disableRandomX) {
m_hasher = new RandomX_Hasher_RPC(this);
}
else {
@@ -252,7 +220,7 @@ p2pool::p2pool(int argc, char* argv[])
p2pool::~p2pool()
{
#ifdef WITH_UPNP
if (m_params->m_upnp) {
if (m_params.m_upnp) {
destroy_upnp();
}
#endif
@@ -295,7 +263,6 @@ p2pool::~p2pool()
delete m_hasher;
delete m_blockTemplate;
delete m_mempool;
delete m_params;
{
auto* p = bkg_jobs_tracker;
@@ -318,7 +285,7 @@ void p2pool::update_host_ping(const std::string& display_name, double ping)
LOGWARN(1, display_name << " ping is " << ping << " ms, this is too high for an efficient mining. Try to use a different node, or your own local node.");
}
const std::vector<Params::Host>& v = m_params->m_hosts;
const std::vector<Params::Host>& v = m_params.m_hosts;
for (size_t i = 0, n = v.size(); i < n; ++i) {
if (v[i].m_displayName == display_name) {
@@ -332,8 +299,8 @@ void p2pool::print_hosts() const
{
const Params::Host& host = current_host();
for (size_t i = 0, n = m_params->m_hosts.size(); i < n; ++i) {
const Params::Host& h = m_params->m_hosts[i];
for (size_t i = 0, n = m_params.m_hosts.size(); i < n; ++i) {
const Params::Host& h = m_params.m_hosts[i];
char buf[64] = {};
if (m_hostPing[i] > 0.0) {
@@ -417,7 +384,7 @@ void p2pool::handle_tx(TxMempoolData& tx)
}
#if TEST_MEMPOOL_PICKING_ALGORITHM
m_blockTemplate->update(miner_data(), *m_mempool, &m_params->m_wallet);
m_blockTemplate->update(miner_data(), *m_mempool, &m_params.m_wallet);
#endif
m_zmqLastActive = seconds_since_epoch();
@@ -557,7 +524,7 @@ void p2pool::get_missing_heights()
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,
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;
@@ -801,14 +768,14 @@ void p2pool::update_aux_data(const hash& chain_id)
void p2pool::send_aux_job_donation()
{
#ifdef WITH_TLS
if (m_params->m_authorKeyFile.empty()) {
if (m_params.m_authorKeyFile.empty()) {
return;
}
std::ifstream f(m_params->m_authorKeyFile, std::ios::binary | std::ios::ate);
std::ifstream f(m_params.m_authorKeyFile, std::ios::binary | std::ios::ate);
if (!f.good()) {
LOGERR(1, "send_aux_job_donation: failed to open " << m_params->m_authorKeyFile);
LOGERR(1, "send_aux_job_donation: failed to open " << m_params.m_authorKeyFile);
return;
}
@@ -816,7 +783,7 @@ void p2pool::send_aux_job_donation()
ON_SCOPE_LEAVE([&key](){ secure_zero_memory(key); });
if (f.tellg() != static_cast<std::streampos>(sizeof(key))) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << " has an invalid size");
LOGERR(1, "send_aux_job_donation: " << m_params.m_authorKeyFile << " has an invalid size");
return;
}
@@ -824,21 +791,21 @@ void p2pool::send_aux_job_donation()
f.read(reinterpret_cast<char*>(&key), sizeof(key));
if (!f.good()) {
LOGERR(1, "send_aux_job_donation: failed to read data from " << m_params->m_authorKeyFile);
LOGERR(1, "send_aux_job_donation: failed to read data from " << m_params.m_authorKeyFile);
return;
}
const uint64_t timestamp = time(nullptr);
if (timestamp >= read_unaligned(reinterpret_cast<uint64_t*>(key.expiration_time))) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << " is expired");
LOGERR(1, "send_aux_job_donation: " << m_params.m_authorKeyFile << " is expired");
return;
}
const uint8_t* p = reinterpret_cast<uint8_t*>(&key);
if (!ED25519_verify(p, sizeof(key.pub_key) + sizeof(key.expiration_time), key.master_key_signature, ED25519_MASTER_PUBLIC_KEY)) {
LOGERR(1, "send_aux_job_donation: " << m_params->m_authorKeyFile << ": signature verification failed");
LOGERR(1, "send_aux_job_donation: " << m_params.m_authorKeyFile << ": signature verification failed");
return;
}
@@ -1162,7 +1129,7 @@ void p2pool::submit_block() const
const uint64_t t1 = microseconds_since_epoch();
JSONRPCRequest::call(host.m_address, host.m_rpcPort, request, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, request, host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[height, diff, template_id, nonce, extra_nonce, merge_mining_root, is_external](const char* data, size_t size, double)
{
rapidjson::Document doc;
@@ -1281,7 +1248,7 @@ void p2pool::download_block_headers1(uint64_t current_height)
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << prev_seed_height << "}}" << '\0';
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, prev_seed_height, current_height](const char* data, size_t size, double) {
ChainMain block;
if (parse_block_header(data, size, block)) {
@@ -1314,7 +1281,7 @@ void p2pool::download_block_headers2(uint64_t current_height)
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << seed_height << "}}" << '\0';
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, seed_height, current_height](const char* data, size_t size, double) {
ChainMain block;
if (parse_block_header(data, size, block)) {
@@ -1350,7 +1317,7 @@ void p2pool::download_block_headers3(uint64_t start_height, uint64_t current_hei
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << next_height << "}}" << '\0';
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, start_height, next_height, current_height](const char* data, size_t size, double) {
if (parse_block_headers_range(data, size) == next_height - start_height + 1) {
download_block_headers3(next_height + 1, current_height);
@@ -1383,7 +1350,7 @@ void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_hei
s.m_pos = 0;
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << current_height - 1 << "}}" << '\0';
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, start_height, current_height, host](const char* data, size_t size, double)
{
if (parse_block_headers_range(data, size) == current_height - start_height) {
@@ -1392,14 +1359,14 @@ void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_hei
m_p2pServer = new P2PServer(this);
m_stratumServer = new StratumServer(this);
#if defined(WITH_RANDOMX) && !defined(P2POOL_UNIT_TESTS)
if (m_params->m_minerThreads) {
start_mining(m_params->m_minerThreads);
if (m_params.m_minerThreads) {
start_mining(m_params.m_minerThreads);
}
{
WriteLock lock(m_ZMQReaderLock);
try {
m_ZMQReader = new ZMQReader(host.m_address, host.m_zmqPort, m_params->m_socks5Proxy, this);
m_ZMQReader = new ZMQReader(host.m_address, host.m_zmqPort, m_params.m_socks5Proxy, this);
m_zmqLastActive = seconds_since_epoch();
}
catch (const std::exception& e) {
@@ -1413,10 +1380,10 @@ void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_hei
get_miner_data();
// Get ping times for all other hosts
for (const Params::Host& h : m_params->m_hosts) {
for (const Params::Host& h : m_params.m_hosts) {
const std::string& name = h.m_displayName;
if (name != host.m_displayName) {
JSONRPCRequest::call(h.m_address, h.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_version\"}", h.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(h.m_address, h.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_version\"}", h.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, name](const char*, size_t, double tcp_ping) { update_host_ping(name, tcp_ping); },
[](const char*, size_t, double) {});
}
@@ -1424,7 +1391,7 @@ void p2pool::download_block_headers4(uint64_t start_height, uint64_t current_hei
std::vector<IMergeMiningClient*> merge_mining_clients;
for (const auto& h : m_params->m_mergeMiningHosts) {
for (const auto& h : m_params.m_mergeMiningHosts) {
IMergeMiningClient* c = IMergeMiningClient::create(this, h.m_host, h.m_wallet);
if (c) {
merge_mining_clients.push_back(c);
@@ -1525,7 +1492,7 @@ void p2pool::get_info()
{
const Params::Host& host = current_host();
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_info\"}", host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_info\"}", host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this](const char* data, size_t size, double)
{
parse_get_info_rpc(data, size);
@@ -1549,7 +1516,7 @@ void p2pool::load_found_blocks()
return;
}
std::ifstream f(DATA_DIR + FOUND_BLOCKS_FILE);
std::ifstream f(m_params.m_dataDir + FOUND_BLOCKS_FILE);
if (!f.is_open()) {
return;
}
@@ -1644,7 +1611,7 @@ void p2pool::get_version()
{
const Params::Host& host = current_host();
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_version\"}", host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_version\"}", host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this](const char* data, size_t size, double)
{
parse_get_version_rpc(data, size);
@@ -1721,7 +1688,7 @@ void p2pool::get_miner_data(bool retry)
const Params::Host& host = current_host();
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}", host.m_rpcLogin, m_params->m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}", host.m_rpcLogin, m_params.m_socks5Proxy, host.m_rpcSSL, host.m_rpcSSL_Fingerprint,
[this, host](const char* data, size_t size, double tcp_ping)
{
parse_get_miner_data_rpc(data, size);
@@ -2085,7 +2052,7 @@ void p2pool::api_update_block_found(const ChainMain* data, const PoolBlock* bloc
difficulty_type diff;
if (data && get_difficulty_at_height(data->height, diff)) {
const std::string path = DATA_DIR + FOUND_BLOCKS_FILE;
const std::string path = m_params.m_dataDir + FOUND_BLOCKS_FILE;
std::ofstream f(path, std::ios::app);
if (f.is_open()) {
f << cur_time << ' ' << data->height << ' ' << data->id << ' ' << diff << ' ' << total_hashes << '\n';
@@ -2141,7 +2108,7 @@ void p2pool::on_external_block(const PoolBlock& block)
void p2pool::api_update_aux_data()
{
if (!m_api || !m_params->m_localStats || m_stopped) {
if (!m_api || !m_params.m_localStats || m_stopped) {
return;
}
@@ -2291,7 +2258,7 @@ bool p2pool::zmq_running() const
const Params::Host& p2pool::switch_host()
{
const std::vector<Params::Host>& v = m_params->m_hosts;
const std::vector<Params::Host>& v = m_params.m_hosts;
return v[++m_currentHostIndex % v.size()];
}
@@ -2316,7 +2283,7 @@ void p2pool::reconnect_to_host()
m_ZMQReader = nullptr;
try {
ZMQReader* new_reader = new ZMQReader(new_host.m_address, new_host.m_zmqPort, m_params->m_socks5Proxy, this);
ZMQReader* new_reader = new ZMQReader(new_host.m_address, new_host.m_zmqPort, m_params.m_socks5Proxy, this);
m_zmqLastActive = seconds_since_epoch();
m_ZMQReader = new_reader;
}
@@ -2332,7 +2299,7 @@ void p2pool::reconnect_to_host()
int p2pool::run()
{
if (!m_params->valid()) {
if (!m_params.valid()) {
LOGERR(1, "Invalid or missing command line. Try \"p2pool --help\".");
return 1;
}
@@ -2343,8 +2310,8 @@ int p2pool::run()
}
#ifdef WITH_TLS
if (!m_params->m_tlsCert.empty() && !m_params->m_tlsCertKey.empty()) {
if (!ServerTls::load_from_files(m_params->m_tlsCert.c_str(), m_params->m_tlsCertKey.c_str())) {
if (!m_params.m_tlsCert.empty() && !m_params.m_tlsCertKey.empty()) {
if (!ServerTls::load_from_files(m_params.m_tlsCert.c_str(), m_params.m_tlsCertKey.c_str())) {
LOGERR(1, "Failed to load TLS files");
return 1;
}
+4 -4
View File
@@ -40,7 +40,7 @@ struct PoolBlock;
class p2pool : public MinerCallbackHandler, public nocopy_nomove
{
public:
p2pool(int argc, char* argv[]);
explicit p2pool(const Params& params);
~p2pool() override;
int run();
@@ -48,13 +48,13 @@ public:
bool stopped() const { return m_stopped; }
void stop();
const Params& params() const { return *m_params; }
const Params& params() const { return m_params; }
BlockTemplate& block_template() { return *m_blockTemplate; }
SideChain& side_chain() { return *m_sideChain; }
FORCEINLINE const Params::Host& current_host() const
{
const std::vector<Params::Host>& v = m_params->m_hosts;
const std::vector<Params::Host>& v = m_params.m_hosts;
return v[m_currentHostIndex % v.size()];
}
@@ -158,7 +158,7 @@ private:
std::atomic<bool> m_stopped;
const Params* m_params;
const Params& m_params;
std::vector<double> m_hostPing;
std::atomic<uint32_t> m_currentHostIndex;
+136 -73
View File
@@ -19,6 +19,7 @@
#include "params.h"
#include "stratum_server.h"
#include "p2p_server.h"
#include <fstream>
LOG_CATEGORY(Params)
@@ -29,13 +30,21 @@ namespace p2pool {
static constexpr uint64_t MIN_STRATUM_BAN_TIME = UINT64_C(1);
static constexpr uint64_t MAX_STRATUM_BAN_TIME = (UINT64_C(1) << 34) - 1;
Params::Params(int argc, char* const argv[])
Params::Params(const std::vector<std::vector<std::string>>& args)
{
for (int i = 1; i < argc; ++i) {
auto has1 = [](const auto& v) { return (v.size() > 1) && !v[1].empty();};
auto has2 = [](const auto& v) { return (v.size() > 2) && !v[2].empty();};
for (const auto& arg : args) {
// Ignore empty parameters
if (arg.empty() || arg[0].empty()) {
continue;
}
bool ok = false;
if ((strcmp(argv[i], "--host") == 0) && (i + 1 < argc)) {
const char* address = argv[++i];
if ((arg[0] == "host") && has1(arg)) {
const char* address = arg[1].c_str();
if (m_hosts.empty()) {
m_hosts.emplace_back();
@@ -49,31 +58,31 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if ((strcmp(argv[i], "--rpc-port") == 0) && (i + 1 < argc)) {
if ((arg[0] == "rpc-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcPort = static_cast<int32_t>(std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL));
m_hosts.back().m_rpcPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
if ((strcmp(argv[i], "--zmq-port") == 0) && (i + 1 < argc)) {
if ((arg[0] == "zmq-port") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_zmqPort = static_cast<int32_t>(std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL));
m_hosts.back().m_zmqPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
if (strcmp(argv[i], "--light-mode") == 0) {
if (arg[0] == "light-mode") {
m_lightMode = true;
ok = true;
}
if ((strcmp(argv[i], "--wallet") == 0) && (i + 1 < argc)) {
const char* s = argv[++i];
if ((arg[0] == "wallet") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_mainWallet.decode(s)) {
LOGERR(1, "Wallet " << s << " failed to decode");
@@ -82,8 +91,8 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if ((strcmp(argv[i], "--subaddress") == 0) && (i + 1 < argc)) {
const char* s = argv[++i];
if ((arg[0] == "subaddress") && has1(arg)) {
const char* s = arg[1].c_str();
if (!m_subaddress.decode(s)) {
LOGERR(1, "Subaddress " << s << " failed to decode");
@@ -92,111 +101,115 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if ((strcmp(argv[i], "--stratum") == 0) && (i + 1 < argc)) {
m_stratumAddresses = argv[++i];
if ((arg[0] == "stratum") && has1(arg)) {
m_stratumAddresses = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--stratum-ban-time") == 0) && (i + 1 < argc)) {
m_stratumBanTime = strtoull(argv[++i], nullptr, 10);
if ((arg[0] == "stratum-ban-time") && has1(arg)) {
m_stratumBanTime = strtoull(arg[1].c_str(), nullptr, 10);
ok = true;
}
if ((strcmp(argv[i], "--p2p") == 0) && (i + 1 < argc)) {
m_p2pAddresses = argv[++i];
if ((arg[0] == "p2p") && has1(arg)) {
m_p2pAddresses = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--addpeers") == 0) && (i + 1 < argc)) {
m_p2pPeerList = argv[++i];
if ((arg[0] == "addpeers") && has1(arg)) {
m_p2pPeerList = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--loglevel") == 0) && (i + 1 < argc)) {
const int level = std::min(std::max<int>(static_cast<int>(strtol(argv[++i], nullptr, 10)), 0), log::MAX_GLOBAL_LOG_LEVEL);
if ((arg[0] == "loglevel") && has1(arg)) {
const int level = std::min(std::max<int>(static_cast<int>(strtol(arg[1].c_str(), nullptr, 10)), 0), log::MAX_GLOBAL_LOG_LEVEL);
log::GLOBAL_LOG_LEVEL = level;
ok = true;
}
if ((strcmp(argv[i], "--data-dir") == 0) && (i + 1 < argc)) {
// Processed in main.cpp
++i;
if ((arg[0] == "data-dir") && has1(arg)) {
m_dataDir = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--sidechain-config") == 0) && (i + 1 < argc)) {
m_sidechainConfig = argv[++i];
if ((arg[0] == "log-file") && has1(arg)) {
m_logFilePath = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--data-api") == 0) && (i + 1 < argc)) {
m_apiPath = argv[++i];
if ((arg[0] == "sidechain-config") && has1(arg)) {
m_sidechainConfig = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--local-api") == 0) || (strcmp(argv[i], "--stratum-api") == 0)) {
if ((arg[0] == "data-api") && has1(arg)) {
m_apiPath = arg[1];
ok = true;
}
if ((arg[0] == "local-api") || (arg[0] == "stratum-api")) {
m_localStats = true;
ok = true;
}
if (strcmp(argv[i], "--no-cache") == 0) {
if (arg[0] == "no-cache") {
m_blockCache = false;
ok = true;
}
if (strcmp(argv[i], "--no-color") == 0) {
if (arg[0] == "no-color") {
log::CONSOLE_COLORS = false;
ok = true;
}
#ifdef WITH_RANDOMX
if (strcmp(argv[i], "--no-randomx") == 0) {
if (arg[0] == "no-randomx") {
m_disableRandomX = true;
ok = true;
}
#endif
if ((!strcmp(argv[i], "--out-peers") || !strcmp(argv[i], "--outpeers")) && (i + 1 < argc)) {
m_maxOutgoingPeers = std::min(std::max(strtoul(argv[++i], nullptr, 10), 10UL), 450UL);
if (((arg[0] == "out-peers") || (arg[0] == "outpeers")) && has1(arg)) {
m_maxOutgoingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
ok = true;
}
if ((!strcmp(argv[i], "--in-peers") || !strcmp(argv[i], "--inpeers")) && (i + 1 < argc)) {
m_maxIncomingPeers = std::min(std::max(strtoul(argv[++i], nullptr, 10), 10UL), 450UL);
if (((arg[0] == "in-peers") || (arg[0] == "inpeers")) && has1(arg)) {
m_maxIncomingPeers = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 10UL), 450UL);
ok = true;
}
if ((strcmp(argv[i], "--start-mining") == 0) && (i + 1 < argc)) {
m_minerThreads = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 64UL);
if ((arg[0] == "start-mining") && has1(arg)) {
m_minerThreads = std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 64UL);
ok = true;
}
if (strcmp(argv[i], "--mini") == 0) {
if (arg[0] == "mini") {
m_mini = true;
ok = true;
}
if (strcmp(argv[i], "--nano") == 0) {
if (arg[0] == "nano") {
m_nano = true;
ok = true;
}
if (strcmp(argv[i], "--no-autodiff") == 0) {
if (arg[0] == "no-autodiff") {
m_autoDiff = false;
ok = true;
}
if ((strcmp(argv[i], "--rpc-login") == 0) && (i + 1 < argc)) {
if ((arg[0] == "rpc-login") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcLogin = argv[++i];
m_hosts.back().m_rpcLogin = arg[1];
ok = true;
}
#ifdef WITH_TLS
if (strcmp(argv[i], "--rpc-ssl") == 0) {
if (arg[0] == "rpc-ssl") {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
@@ -205,94 +218,90 @@ Params::Params(int argc, char* const argv[])
ok = true;
}
if ((strcmp(argv[i], "--rpc-ssl-fingerprint") == 0) && (i + 1 < argc)) {
if ((arg[0] == "rpc-ssl-fingerprint") && has1(arg)) {
if (m_hosts.empty()) {
m_hosts.emplace_back();
}
m_hosts.back().m_rpcSSL_Fingerprint = argv[++i];
m_hosts.back().m_rpcSSL_Fingerprint = arg[1];
ok = true;
}
#endif
if ((strcmp(argv[i], "--socks5") == 0) && (i + 1 < argc)) {
m_socks5Proxy = argv[++i];
if ((arg[0] == "socks5") && has1(arg)) {
m_socks5Proxy = arg[1];
ok = true;
}
if (strcmp(argv[i], "--no-dns") == 0) {
if (arg[0] == "no-dns") {
m_dns = false;
disable_resolve_host = true;
ok = true;
}
if ((strcmp(argv[i], "--p2p-external-port") == 0) && (i + 1 < argc)) {
m_p2pExternalPort = static_cast<int32_t>(std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL));
if ((arg[0] == "p2p-external-port") && has1(arg)) {
m_p2pExternalPort = static_cast<int32_t>(std::min(std::max(strtoul(arg[1].c_str(), nullptr, 10), 1UL), 65535UL));
ok = true;
}
#ifdef WITH_UPNP
if ((strcmp(argv[i], "--no-upnp") == 0) || (strcmp(argv[i], "--no-igd") == 0)) {
if ((arg[0] == "no-upnp") || (arg[0] == "no-igd")) {
m_upnp = false;
ok = true;
}
if (strcmp(argv[i], "--upnp-stratum") == 0) {
if (arg[0] == "upnp-stratum") {
m_upnpStratum = true;
ok = true;
}
#endif
if ((strcmp(argv[i], "--merge-mine") == 0) && (i + 2 < argc)) {
m_mergeMiningHosts.emplace_back(argv[i + 1], argv[i + 2]);
i += 2;
if ((arg[0] == "merge-mine") && has1(arg) && has2(arg)) {
m_mergeMiningHosts.emplace_back(arg[1], arg[2]);
ok = true;
}
#ifdef WITH_TLS
if ((strcmp(argv[i], "--tls-cert") == 0) && (i + 1 < argc)) {
m_tlsCert = argv[++i];
if ((arg[0] == "tls-cert") && has1(arg)) {
m_tlsCert = arg[1];
ok = true;
}
if ((strcmp(argv[i], "--tls-cert-key") == 0) && (i + 1 < argc)) {
m_tlsCertKey = argv[++i];
if ((arg[0] == "tls-cert-key") && has1(arg)) {
m_tlsCertKey = arg[1];
ok = true;
}
#endif
if (strcmp(argv[i], "--no-stratum-http") == 0) {
if (arg[0] == "no-stratum-http") {
m_enableStratumHTTP = false;
ok = true;
}
#ifdef WITH_MERGE_MINING_DONATION
if ((strcmp(argv[i], "--adkf") == 0) && (i + 1 < argc)) {
m_authorKeyFile = argv[++i];
if ((arg[0] == "adkf") && has1(arg)) {
m_authorKeyFile = arg[1];
ok = true;
}
#endif
if (strcmp(argv[i], "--full-validation") == 0) {
if (arg[0] == "full-validation") {
m_enableFullValidation = true;
ok = true;
}
if ((strcmp(argv[i], "--onion-address") == 0) && (i + 1 < argc)) {
m_onionAddress = argv[++i];
if ((arg[0] == "onion-address") && has1(arg)) {
m_onionAddress = arg[1];
ok = true;
}
if (strcmp(argv[i], "--no-clearnet-p2p") == 0) {
if (arg[0] == "no-clearnet-p2p") {
m_noClearnetP2P = 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));
fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]);
fprintf(stderr, "Unknown or invalid command line parameter \"%s\"\n\n", arg[0].c_str());
p2pool_usage();
throw std::exception();
}
@@ -322,6 +331,23 @@ Params::Params(int argc, char* const argv[])
m_hosts.emplace_back();
}
const int p2p_port = m_mini ? DEFAULT_P2P_PORT_MINI : (m_nano ? DEFAULT_P2P_PORT_NANO : DEFAULT_P2P_PORT);
if (m_noClearnetP2P) {
char buf[48] = {};
log::Stream s(buf);
s << "127.0.0.1:" << p2p_port;
m_p2pAddresses = buf;
}
else if (m_p2pAddresses.empty()) {
char buf[48] = {};
log::Stream s(buf);
s << "[::]:" << p2p_port << ",0.0.0.0:" << p2p_port;
m_p2pAddresses = buf;
}
if (m_stratumAddresses.empty()) {
const int stratum_port = DEFAULT_STRATUM_PORT;
@@ -358,6 +384,43 @@ Params::Params(int argc, char* const argv[])
}
m_displayWallet.assign(display_wallet_buf, Wallet::ADDRESS_LENGTH);
for (Params::Host& h : m_hosts) {
if (!h.init_display_name(*this)) {
throw std::exception();
}
}
// If the data directory is not set, check if P2Pool has write access to the current directory
// If it doesn't, switch to user's home directory
if (m_dataDir.empty()) {
std::ofstream f("p2pool.tmp");
if (f && f.put(' ')) {
f.close();
std::remove("p2pool.tmp");
}
else {
char buf[1024];
size_t size = sizeof(buf);
if (uv_os_homedir(buf, &size) == 0) {
m_dataDir.assign(buf, size);
fixup_path(m_dataDir);
m_dataDir += ".p2pool/";
if (m_mini) {
m_dataDir += "mini/";
}
else if (m_nano) {
m_dataDir += "nano/";
}
}
}
}
else {
fixup_path(m_dataDir);
}
}
bool Params::valid() const
+5 -2
View File
@@ -29,7 +29,7 @@ struct Params
FORCEINLINE Params() {}
#endif
Params(int argc, char* const argv[]);
explicit Params(const std::vector<std::vector<std::string>>& args);
bool valid() const;
@@ -65,7 +65,8 @@ struct Params
struct MergeMiningHost
{
MergeMiningHost(const char* host, const char* wallet) : m_host(host), m_wallet(wallet) {}
template<typename T>
FORCEINLINE MergeMiningHost(const T& host, const T& wallet) : m_host(host), m_wallet(wallet) {}
std::string m_host;
std::string m_wallet;
@@ -85,6 +86,8 @@ struct Params
std::string m_stratumAddresses;
std::string m_p2pAddresses;
std::string m_p2pPeerList;
std::string m_dataDir;
std::string m_logFilePath;
std::string m_sidechainConfig;
std::string m_apiPath;
uint64_t m_stratumBanTime = DEFAULT_STRATUM_BAN_TIME;
+2 -2
View File
@@ -444,7 +444,7 @@ void RandomX_Hasher_RPC::loop(void* data)
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, bool /*force_light_mode*/)
bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t height, const hash& seed, hash& h, bool /*force_light_mode*/)
{
MutexLock lock(m_requestMutex);
@@ -456,7 +456,7 @@ bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t h
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\":\"\"}}" << '\0';
",\"seed_hash\":\"" << seed << "\"}}" << '\0';
std::atomic<int> result{ 0 };
std::atomic<bool> done{ false };
+111 -2
View File
@@ -27,6 +27,7 @@ extern "C" {
#include <map>
#include <istream>
#include <ostream>
#include <fstream>
#if !defined(_WIN32) && defined(HAVE_SCHED)
#include <sched.h>
@@ -159,8 +160,6 @@ secure_zero_memory(volatile void* data, size_t size)
const uint8_t ED25519_MASTER_PUBLIC_KEY[32] = {51,175,37,73,203,241,188,115,195,255,123,53,218,120,90,74,186,240,82,178,67,139,124,91,180,106,188,181,187,51,236,10};
std::string DATA_DIR;
SoftwareID get_software_id(uint32_t value)
{
switch (value) {
@@ -1035,4 +1034,114 @@ hash from_onion_v3(const std::string& address)
return result;
}
std::vector<std::vector<std::string>> parse_config(const std::string& file_name)
{
std::ifstream f(file_name);
if (!f.is_open() || !f.good()) {
throw std::exception();
}
std::vector<std::vector<std::string>> args;
auto is_alpha = [](char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); };
auto is_num = [](char c) { return ('0' <= c && c <= '9'); };
std::string s;
while (f.good() && std::getline(f, s)) {
if (s.empty()) {
continue;
}
bool quoted = false;
enum {
BEFORE_NAME,
COMMENT,
NAME,
AFTER_NAME,
VALUE,
VALUE_ESCAPE_CHAR,
} state = BEFORE_NAME;
for (const char c : s) {
switch (state) {
case BEFORE_NAME:
if (is_alpha(c)) {
state = NAME;
args.emplace_back(1, std::string(1, c));
}
else if (c == '#') {
state = COMMENT;
}
break;
case COMMENT:
break;
case NAME:
if (is_alpha(c) || is_num(c) || (c == '-')) {
args.back()[0] += c;
}
else if (c == '#') {
state = COMMENT;
}
else {
state = AFTER_NAME;
}
break;
case AFTER_NAME:
if (c == '#') {
state = COMMENT;
}
else if ((c != '\t') && (c != ' ') && (c != '=')) {
state = VALUE;
quoted = (c == '"');
if (quoted) {
args.back().emplace_back();
}
else {
args.back().emplace_back(1, c);
}
}
break;
case VALUE:
if (quoted) {
if (c == '"') {
state = AFTER_NAME;
}
else if (c == '\\') {
state = VALUE_ESCAPE_CHAR;
}
else {
args.back().back() += c;
}
}
else {
if (c == ' ') {
state = AFTER_NAME;
}
else if (c == '#') {
state = COMMENT;
}
else {
args.back().back() += c;
}
}
break;
case VALUE_ESCAPE_CHAR:
args.back().back() += c;
state = VALUE;
break;
}
}
}
return args;
}
} // namespace p2pool
+3 -3
View File
@@ -35,7 +35,7 @@
namespace p2pool {
#define P2POOL_VERSION_MAJOR 4
#define P2POOL_VERSION_MINOR 12
#define P2POOL_VERSION_MINOR 13
#define P2POOL_VERSION_PATCH 0
constexpr uint32_t P2POOL_VERSION = (P2POOL_VERSION_MAJOR << 16) | (P2POOL_VERSION_MINOR << 8) | P2POOL_VERSION_PATCH;
@@ -44,8 +44,6 @@ extern const char* VERSION;
extern const uint8_t ED25519_MASTER_PUBLIC_KEY[32];
extern std::string DATA_DIR;
enum class SoftwareID : uint32_t {
P2Pool = 0,
GoObserver = 0x624F6F47UL,
@@ -443,6 +441,8 @@ static FORCEINLINE constexpr hash from_onion_v3_const(const char* address)
return result;
}
std::vector<std::vector<std::string>> parse_config(const std::string& file_name);
} // namespace p2pool
void memory_tracking_start();
+1
View File
@@ -191,3 +191,4 @@ add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMA
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/sidechain_dump.dat.xz" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/sidechain_dump_mini.dat.xz" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/sidechain_dump_nano.dat.xz" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/test_params.conf" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
+7 -7
View File
@@ -58,7 +58,7 @@ TEST(block_template, update)
params.m_miningWallet = Wallet("44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg");
// Test 1: empty template
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
ASSERT_EQ(tpl.get_reward(), 600000000000ULL);
const PoolBlock* b = tpl.pool_block_template();
@@ -113,7 +113,7 @@ TEST(block_template, update)
}
ASSERT_EQ(mempool.size(), 512);
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
ASSERT_EQ(tpl.get_reward(), 612054770773ULL);
ASSERT_EQ(b->m_sidechainId, H("c9df4853003ab436416b9fc9a5a072d16b4dede849e697a8be2ebb9c88c8ec72"));
@@ -154,7 +154,7 @@ TEST(block_template, update)
data.aux_chains.emplace_back(H("01f0cf665bd4cd31cbb2b2470236389c483522b350335e10a4a5dca34cb85990"), H("d9de1cfba7cdbd47f12f77addcb39b24c1ae7a16c35372bf28d6aee5d7579ee6"), difficulty_type(1000000));
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
ASSERT_EQ(tpl.get_reward(), 600300000000ULL);
ASSERT_EQ(b->m_sidechainId, H("c32abac2cad40e263a94f5f43f90e0a7d7d4b151305b79951dbc8c88c3180613"));
@@ -191,7 +191,7 @@ TEST(block_template, update)
}
ASSERT_EQ(mempool.size(), 10000);
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
ASSERT_EQ(tpl.get_reward(), 619742028747ULL);
ASSERT_EQ(b->m_sidechainId, H("69e7dd43dd99ac6be3f57ca333cc0d814189e83aee1773c99a341aca085c0d46"));
@@ -251,13 +251,13 @@ TEST(block_template, submit_sidechain_block)
std::mt19937_64 rng(101112);
for (uint64_t i = 0, i2 = 0, i3 = 0; i < sidechain.chain_window_size() * 3; ++i) {
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
if ((rng() % 31) == 0) {
tpl2.update(data, mempool, &params);
tpl2.update(data, mempool, params);
if ((rng() % 11) == 0) {
tpl3.update(data, mempool, &params);
tpl3.update(data, mempool, params);
++i3;
ASSERT_TRUE(tpl3.submit_sidechain_block(i3, 0, 0));
}
+1 -1
View File
@@ -252,7 +252,7 @@ TEST(pool_block, verify)
params.m_miningWallet = Wallet("44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg");
params.m_subaddress = Wallet("86eQxzSW4AZfvsWRSop755WZUsog6L3x32NRZukeeShnS4mBGVpcqQhS6pCNxj44usPKNwesZ45ooHyjDku6nVZdT3Q9qrz");
tpl.update(data, mempool, &params);
tpl.update(data, mempool, params);
std::vector<uint8_t> blobs;
uint64_t height;
+17
View File
@@ -0,0 +1,17 @@
# comment 1
param1=value1
param2 = value2 # comment 2
param3 value3#_comment_3
param4 = "value with spaces # not a comment" # a real comment
param5 = "spaces and quotes \" and \\ slashes"
param6 = value1 value2 value3
param7=value7
param8#comment
param9
abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789=0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz=://
+61
View File
@@ -247,4 +247,65 @@ TEST(util, onion)
ASSERT_TRUE(from_onion_v3("civ5tgldg3yx73ytse6hvvk3nm6q3zctbqvytpszihm35b33ze73kxad.onion").empty());
}
TEST(util, parse_config)
{
const std::vector<std::vector<std::string>> args = parse_config("test_params.conf");
ASSERT_EQ(args.size(), 10);
ASSERT_EQ(args[0].size(), 2);
ASSERT_EQ(args[0][0], "param1");
ASSERT_EQ(args[0][1], "value1");
ASSERT_EQ(args[1].size(), 2);
ASSERT_EQ(args[1][0], "param2");
ASSERT_EQ(args[1][1], "value2");
ASSERT_EQ(args[2].size(), 2);
ASSERT_EQ(args[2][0], "param3");
ASSERT_EQ(args[2][1], "value3");
ASSERT_EQ(args[3].size(), 2);
ASSERT_EQ(args[3][0], "param4");
ASSERT_EQ(args[3][1], "value with spaces # not a comment");
ASSERT_EQ(args[4].size(), 2);
ASSERT_EQ(args[4][0], "param5");
ASSERT_EQ(args[4][1], "spaces and quotes \" and \\ slashes");
ASSERT_EQ(args[5].size(), 4);
ASSERT_EQ(args[5][0], "param6");
ASSERT_EQ(args[5][1], "value1");
ASSERT_EQ(args[5][2], "value2");
ASSERT_EQ(args[5][3], "value3");
ASSERT_EQ(args[6].size(), 2);
ASSERT_EQ(args[6][0], "param7");
ASSERT_EQ(args[6][1], "value7");
ASSERT_EQ(args[7].size(), 1);
ASSERT_EQ(args[7][0], "param8");
ASSERT_EQ(args[8].size(), 1);
ASSERT_EQ(args[8][0], "param9");
ASSERT_EQ(args[9].size(), 2);
ASSERT_EQ(args[9][0], "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789");
ASSERT_EQ(args[9][1], "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz=://");
bool exception_thrown = false;
try {
parse_config("non_existent_file.conf");
// Execution shouldn't reach this line
FAIL();
}
catch (const std::exception&) {
exception_thrown = true;
}
ASSERT_TRUE(exception_thrown);
}
}