Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8582b2a0f | |||
| 8493dbc47b | |||
| 602b9e2ae9 | |||
| 103a2cbd4f | |||
| e4b11ecab4 | |||
| 781606bec5 | |||
| f4d709c0dd | |||
| 8699e1887c | |||
| bf39319cbb | |||
| e92ce0a5f3 | |||
| f7b90b3808 | |||
| 837a33480e | |||
| 7b02c3d24a | |||
| c59845e746 | |||
| 119782920a | |||
| 30ba38c2b3 | |||
| 87547576de | |||
| 5febb8c4e2 | |||
| ddc6986401 | |||
| c0cabc9739 | |||
| 9a1da5b7c2 | |||
| 5daa2b9dff | |||
| 5988acb12b | |||
| 011d05f7b6 | |||
| 294d1a525e | |||
| e5770a5343 | |||
| 7a65e1feb5 | |||
| 4e55f53fb4 | |||
| 4d944d3dc3 | |||
| 3d3b4837ff | |||
| 8270e0898b | |||
| 2ed63ab3ac | |||
| d99a48d87d | |||
| 27375e7382 | |||
| a81d3c4989 | |||
| b922440fc7 | |||
| 6ca6f2ed3d | |||
| 954b9252c1 | |||
| e355f45544 | |||
| ed32664b9e | |||
| 8619057224 | |||
| 10978c59e4 | |||
| ed56206c30 | |||
| 513c2dfc3b | |||
| 0b544bf55a | |||
| a9d39f0803 | |||
| 2248739dd5 | |||
| b83b691714 | |||
| 887611c9d8 | |||
| 390cf0257e | |||
| 2503dca0e3 | |||
| 8fd45cc977 | |||
| 8d9b9e505e | |||
| 2453c08194 | |||
| f149613d54 | |||
| 2c5cfb6442 | |||
| cfddaf1508 | |||
| 6eff190f87 | |||
| e40c5190b1 | |||
| 2584799415 | |||
| 0463901db7 | |||
| c2704af523 | |||
| 328e9cade9 | |||
| 2b61fff449 | |||
| d8bbe2110e | |||
| 1ef88622d6 | |||
| b1d3fb63f3 | |||
| f44ffd1959 | |||
| e7545db663 | |||
| fcf9d2ad15 | |||
| 7986321a52 | |||
| 8e0f28ee30 | |||
| fecfa18999 | |||
| d8b23cd13c | |||
| 0e0101f507 | |||
| 17a17850ea | |||
| 71d4a6dab0 | |||
| 936d3b5280 | |||
| fac9c23103 | |||
| 3674401923 | |||
| 66d6d0dc33 | |||
| 31ce134413 | |||
| b8e6aae289 | |||
| 8f620712ef | |||
| 1069d1c066 | |||
| bc0634a541 | |||
| 8d65a99fe4 | |||
| 6e68714c26 | |||
| 06ff7b661a | |||
| 70a6442b46 | |||
| 9e7d394ae7 | |||
| 326b2d7a04 | |||
| f3045a5e80 | |||
| b3d72cbfcb | |||
| 76c4573c39 | |||
| 741bec9874 | |||
| 46aed06523 | |||
| 7630c1a883 | |||
| 2877e5dfc1 | |||
| 05b88a48a3 | |||
| c74b567fe4 | |||
| a6b6cb0f09 | |||
| 86e9af6fd7 | |||
| 8776f7dfbb | |||
| 929f908a86 | |||
| 229d7b052a | |||
| a5896f7ae8 | |||
| 114c2cee93 | |||
| 7f413ec994 | |||
| bd30a68e7d | |||
| f4a18726b5 | |||
| 50e284357c | |||
| 2ddb03e2be | |||
| ebae616138 | |||
| 0f88640575 | |||
| 75cc82ae0c | |||
| 32dc235aa5 | |||
| 6ffe1d81c2 | |||
| 5b245e64d3 | |||
| a067361d74 | |||
| a7f66c8883 | |||
| e03e7d831e | |||
| 1219ed0dd6 | |||
| fe2ff95f19 | |||
| d72f0ce40c | |||
| df43e2c126 | |||
| d8ecc1174d | |||
| 3e269b49d4 | |||
| 72c9f3b0db | |||
| 2f5b0db786 | |||
| 8d9f16c387 | |||
| d6cb0ee8a0 | |||
| 5444701c38 | |||
| 396479c2bf | |||
| d78885dcd4 | |||
| ede72ff1d8 | |||
| e5bf27030d | |||
| 375bf56e2e | |||
| f79be1b343 | |||
| 3554adf0c1 | |||
| a32cc9f0f5 | |||
| 3759fd4ac4 | |||
| ac58e8be2e | |||
| 1c7646f98f | |||
| 1b9d14e89d | |||
| 3c41388eb7 | |||
| a9a2113ea4 | |||
| b5fa34e1a1 | |||
| 192f1d722d | |||
| b857664d27 | |||
| 19491f0994 | |||
| 6738b57ba2 | |||
| 30560e6cf8 | |||
| e1de021fba | |||
| 8b4f05dc78 | |||
| 950330b5f7 | |||
| 9927718e25 | |||
| b7ff4f2c2c | |||
| 47c79459a6 | |||
| 143960937e | |||
| ee16ce10c1 | |||
| 3988a69946 | |||
| 738b2e416e | |||
| b96dfa602b | |||
| 9d6f232dd1 | |||
| d808ba6cbf | |||
| 818fab8909 | |||
| 1ffaf3a292 | |||
| 8e11c3dffd | |||
| a7496dbc02 | |||
| 9e439044de | |||
| 536552b9db | |||
| 183bab110e | |||
| beea3e2184 | |||
| e0a3add5f2 | |||
| fd8e5e4eed | |||
| 6f7139fe28 | |||
| 57d996491e | |||
| ba8e0578ed | |||
| 65b267c497 | |||
| 512064de61 | |||
| 2cdb8b5323 | |||
| d08ac60fd9 | |||
| fbc0159453 | |||
| 3d526cebbc | |||
| 2d10a6a270 | |||
| 5f7ce28682 | |||
| 9d0f835186 | |||
| 3fdadf3eb5 | |||
| cd57ab6ad9 | |||
| eab8a51bb7 | |||
| dbb4efb98a | |||
| a83d6deec1 | |||
| f212de64f5 | |||
| 6a4583f758 | |||
| 325f2dc22f | |||
| 7134187dc9 | |||
| b20db0a117 | |||
| 3c7fcf65a9 | |||
| 4fa344a0f7 | |||
| 9aa748e628 | |||
| bba4f8d0c5 | |||
| be8b38e5cf | |||
| db9e5ba332 | |||
| 689fa14cfd | |||
| fa924171c7 | |||
| 8a222d5e75 | |||
| fcb62894a5 | |||
| c94b627808 | |||
| 754eb78a05 | |||
| 045929ca7c | |||
| 98b2d2057c | |||
| 98a9eb4f18 | |||
| 58d32ffd1f | |||
| 76c3e89faf | |||
| abf48fde02 | |||
| c31d5b7d3c | |||
| f455ce398c | |||
| b498084388 | |||
| 75c156578c | |||
| fd67ec1f86 | |||
| b1041ea8a8 | |||
| 51a075c0df | |||
| 8bf045974f | |||
| 44d2005ab1 | |||
| 21f827112d | |||
| 5f18eed14d | |||
| 7a83fd2f30 | |||
| 6e258bb210 | |||
| 72adfd3126 | |||
| 196b27f3b2 | |||
| ce192670a3 | |||
| 14ab9f462a | |||
| 93365973a7 | |||
| 950ecd6bbc | |||
| 8420f5f1b1 | |||
| 80352f6b30 | |||
| 6ef166ba33 | |||
| 9368b96129 | |||
| 025f0bdd0b | |||
| 2d76846d3c | |||
| f6cc7abac9 | |||
| 572d2251d7 | |||
| 7dd9fb9b47 |
+282
-61
@@ -1,8 +1,110 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build-alpine-static:
|
||||
|
||||
timeout-minutes: 75
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {arch: x86_64, flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -Wno-error=inline"}
|
||||
- {arch: aarch64, flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -Wno-error=inline -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
|
||||
|
||||
steps:
|
||||
- name: Setup Alpine Linux
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: ${{ matrix.config.arch }}
|
||||
|
||||
- name: Install dependencies
|
||||
shell: alpine.sh --root {0}
|
||||
run: |
|
||||
apk add git cmake gcc g++ make
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build libcurl
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_FLAGS="-Os ${{ matrix.config.flags }}" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='-Os ${{ matrix.config.flags }}' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_BINARY=ON -DARCH_ID=${{ matrix.config.arch }}
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run RandomX tests
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
build/p2pool --test
|
||||
build/external/src/RandomX/randomx-tests
|
||||
|
||||
- name: Build tests
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON -DARCH_ID=${{ matrix.config.arch }}
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run tests
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: List directory
|
||||
run: |
|
||||
cd build
|
||||
ls -la
|
||||
file p2pool
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-alpine-static-${{ matrix.config.arch }}
|
||||
path: build/p2pool
|
||||
|
||||
build-ubuntu:
|
||||
|
||||
timeout-minutes: 10
|
||||
@@ -30,19 +132,27 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }}
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }} -DCMAKE_C_FLAGS='-flto=2' -DCMAKE_CXX_FLAGS='-flto=2'
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run RandomX tests
|
||||
run: |
|
||||
build/p2pool --test
|
||||
build/external/src/RandomX/randomx-tests
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }}
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cpp }} -DCMAKE_C_FLAGS='-flto=2' -DCMAKE_CXX_FLAGS='-flto=2'
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run tests
|
||||
run: cd tests/build && ./p2pool_tests
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -55,12 +165,17 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -Wno-error=inline"}
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt update
|
||||
sudo apt install -y git build-essential cmake autoconf libgss-dev gcc-12 g++-12
|
||||
sudo apt install -y git build-essential cmake libgss-dev gcc-12 g++-12
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12
|
||||
|
||||
- name: Checkout repository
|
||||
@@ -71,16 +186,16 @@ jobs:
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
autoreconf -fi
|
||||
./configure CFLAGS='-Os' --without-ssl --without-hyper --without-zlib --without-brotli --without-zstd --without-default-ssl-backend --without-ca-bundle --without-ca-path --without-ca-fallback --without-libpsl --without-libgsasl --without-librtmp --without-winidn --without-libidn2 --without-nghttp2 --without-ngtcp2 --without-nghttp3 --without-quiche --without-msh3 --without-zsh-functions-dir --without-fish-functions-dir --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies --disable-socketpair --disable-doh --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-hsts --disable-alt-svc --disable-ares
|
||||
cmake . -DCMAKE_C_FLAGS="-Os ${{ matrix.config.flags }}" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DBUILD_TESTING=OFF
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
@@ -88,26 +203,34 @@ jobs:
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DCMAKE_CXX_FLAGS='-Os' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='-Os ${{ matrix.config.flags }}' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_LIBS=ON
|
||||
cmake .. -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run RandomX tests
|
||||
run: |
|
||||
build/p2pool --test
|
||||
build/external/src/RandomX/randomx-tests
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_LIBS=ON
|
||||
cmake .. -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run tests
|
||||
run: cd tests/build && ./p2pool_tests
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -117,20 +240,20 @@ jobs:
|
||||
|
||||
build-ubuntu-aarch64:
|
||||
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {os: ubuntu-20.04}
|
||||
- {os: ubuntu-22.04}
|
||||
- {os: ubuntu-20.04, flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
|
||||
- {os: ubuntu-22.04, flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -mfix-cortex-a53-835769 -mfix-cortex-a53-843419"}
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y git build-essential cmake autoconf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu
|
||||
sudo apt install -y git build-essential cmake gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu qemu-user
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
@@ -140,16 +263,16 @@ jobs:
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
autoreconf -fi
|
||||
./configure --host=aarch64-linux-gnu CFLAGS='-Os' --without-ssl --without-hyper --without-zlib --without-brotli --without-zstd --without-default-ssl-backend --without-ca-bundle --without-ca-path --without-ca-fallback --without-libpsl --without-libgsasl --without-librtmp --without-winidn --without-libidn2 --without-nghttp2 --without-ngtcp2 --without-nghttp3 --without-quiche --without-msh3 --without-zsh-functions-dir --without-fish-functions-dir --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies --disable-socketpair --disable-doh --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-hsts --disable-alt-svc --disable-ares
|
||||
cmake . -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_C_FLAGS="-Os ${{ matrix.config.flags }}" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_C_FLAGS='-Os' -DBUILD_TESTING=OFF
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
@@ -157,16 +280,35 @@ jobs:
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_C_FLAGS='-Os' -DCMAKE_CXX_FLAGS='-Os' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='-Os ${{ matrix.config.flags }}' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_STRIP=/usr/bin/aarch64-linux-gnu-strip -DSTATIC_LIBS=ON -DARCH_ID=aarch64
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_STRIP=/usr/bin/aarch64-linux-gnu-strip -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON -DARCH_ID=aarch64
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run RandomX tests
|
||||
run: |
|
||||
qemu-aarch64 -L /usr/aarch64-linux-gnu build/p2pool --test
|
||||
qemu-aarch64 -L /usr/aarch64-linux-gnu build/external/src/RandomX/randomx-tests
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_STRIP=/usr/bin/aarch64-linux-gnu-strip -DCMAKE_C_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DCMAKE_CXX_FLAGS='${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections' -DSTATIC_LIBS=ON -DARCH_ID=aarch64
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
qemu-aarch64 -L /usr/aarch64-linux-gnu ./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -178,6 +320,12 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {c: "gcc", cxx: "g++", flags: "-flto=2 -fuse-linker-plugin -ffunction-sections -Wno-error=maybe-uninitialized -Wno-error=attributes"}
|
||||
- {c: "clang", cxx: "clang++", flags: "-flto -ffunction-sections -fuse-ld=lld -Wno-unused-command-line-argument"}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -192,21 +340,21 @@ jobs:
|
||||
uses: eine/setup-msys2@v2
|
||||
with:
|
||||
update: true
|
||||
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake make autoconf libtool automake
|
||||
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-clang mingw-w64-x86_64-lld mingw-w64-x86_64-cmake make
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
autoreconf -fi
|
||||
./configure CFLAGS='-Os' --without-ssl --without-hyper --without-zlib --without-brotli --without-zstd --without-default-ssl-backend --without-ca-bundle --without-ca-path --without-ca-fallback --without-libpsl --without-libgsasl --without-librtmp --without-winidn --without-libidn2 --without-nghttp2 --without-ngtcp2 --without-nghttp3 --without-quiche --without-msh3 --without-zsh-functions-dir --without-fish-functions-dir --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies --disable-socketpair --disable-doh --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-hsts --disable-alt-svc --disable-ares
|
||||
cmake . -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_C_FLAGS="-Os ${{ matrix.config.flags }}" -DCURL_TARGET_WINDOWS_VERSION=0x0600 -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_FLAGS='-Os' -DBUILD_TESTING=OFF
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
@@ -214,33 +362,39 @@ jobs:
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_FLAGS='-Os' -DCMAKE_CXX_FLAGS='-Os' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DZMQ_HAVE_IPC=OFF
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} -DCMAKE_C_FLAGS='-Os ${{ matrix.config.flags }}' -DCMAKE_CXX_FLAGS='-Os ${{ matrix.config.flags }}' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DZMQ_HAVE_IPC=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Unix Makefiles" -DSTATIC_LIBS=ON
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} -DCMAKE_C_FLAGS="${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections" -DCMAKE_CXX_FLAGS="${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections" -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run RandomX tests
|
||||
run: |
|
||||
build/p2pool.exe --test
|
||||
build/external/src/RandomX/randomx-tests.exe
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Unix Makefiles" -DSTATIC_LIBS=ON
|
||||
cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=${{ matrix.config.c }} -DCMAKE_CXX_COMPILER=${{ matrix.config.cxx }} -DCMAKE_C_FLAGS="${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections" -DCMAKE_CXX_FLAGS="${{ matrix.config.flags }} -Wl,-s -Wl,--gc-sections" -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
./p2pool_tests.exe
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-msys2.exe
|
||||
name: p2pool-msys2-${{ matrix.config.c }}.exe
|
||||
path: build/p2pool.exe
|
||||
|
||||
build-windows-msbuild:
|
||||
@@ -251,9 +405,9 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\", rx: "ON", upnp: "ON"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\", rx: "OFF", upnp: "ON"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\", rx: "OFF", upnp: "OFF"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "ON", upnp: "ON"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "OFF", upnp: "ON"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, vspath: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise", rx: "OFF", upnp: "OFF"}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -269,7 +423,23 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "${{ matrix.config.vs }}" -DWITH_RANDOMX=${{ matrix.config.rx }} -DWITH_UPNP=${{ matrix.config.upnp }}
|
||||
& "${{ matrix.config.msbuild }}msbuild" /m /p:Configuration=Release p2pool.vcxproj
|
||||
& "${{ matrix.config.vspath }}\\MSBuild\\Current\\Bin\\amd64\\msbuild" -v:m /m /p:Configuration=Release p2pool.vcxproj
|
||||
|
||||
- name: Check Windows 7 compatibility
|
||||
shell: cmd
|
||||
run: |
|
||||
call "${{ matrix.config.vspath }}\\VC\\Auxiliary\\Build\\vcvarsall.bat" amd64
|
||||
dumpbin /IMPORTS build/Release/p2pool.exe > 1.txt
|
||||
findstr /R /C:"^ *[0-9A-F][0-9A-F]* [a-zA-Z][a-zA-Z0-9]*$" 1.txt > 2.txt
|
||||
python tests/src/check_win7.py 2.txt
|
||||
|
||||
- name: Run RandomX tests
|
||||
if: matrix.config.rx == 'ON'
|
||||
run: |
|
||||
build/Release/p2pool.exe --test
|
||||
cd build/external/src/RandomX
|
||||
& "${{ matrix.config.vspath }}\\MSBuild\\Current\\Bin\\amd64\\msbuild" -v:m /m /p:Configuration=Release randomx-tests.vcxproj
|
||||
Release/randomx-tests.exe
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
@@ -277,27 +447,24 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "${{ matrix.config.vs }}"
|
||||
& "${{ matrix.config.msbuild }}msbuild" /m /p:Configuration=Debug p2pool_tests.vcxproj
|
||||
& "${{ matrix.config.vspath }}\\MSBuild\\Current\\Bin\\amd64\\msbuild" -v:m /m /p:Configuration=Debug p2pool_tests.vcxproj
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd tests/build/Debug
|
||||
7z x *.gz
|
||||
./p2pool_tests.exe
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-msbuild-${{ matrix.config.os }}-randomx-${{ matrix.config.rx }}-upnp-${{ matrix.config.upnp }}.exe
|
||||
name: p2pool-vs-${{ matrix.config.os }}-randomx-${{ matrix.config.rx }}-upnp-${{ matrix.config.upnp }}.exe
|
||||
path: build/Release/p2pool.exe
|
||||
|
||||
build-macos:
|
||||
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-11, macos-12]
|
||||
timeout-minutes: 20
|
||||
runs-on: macos-11
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -305,22 +472,19 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake autoconf libtool automake
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
autoreconf -fi
|
||||
./configure CFLAGS='-Os' --without-ssl --without-hyper --without-zlib --without-brotli --without-zstd --without-default-ssl-backend --without-ca-bundle --without-ca-path --without-ca-fallback --without-libpsl --without-libgsasl --without-librtmp --without-winidn --without-libidn2 --without-nghttp2 --without-ngtcp2 --without-nghttp3 --without-quiche --without-msh3 --without-zsh-functions-dir --without-fish-functions-dir --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies --disable-socketpair --disable-doh --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-hsts --disable-alt-svc --disable-ares
|
||||
cmake . -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-Os -flto" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j3
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DBUILD_TESTING=OFF
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -flto' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build libzmq
|
||||
@@ -328,33 +492,86 @@ jobs:
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DCMAKE_CXX_FLAGS='-Os' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -flto' -DCMAKE_CXX_FLAGS='-Os -flto' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_BINARY=ON
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-flto" -DCMAKE_CXX_FLAGS="-flto" -DSTATIC_LIBS=ON
|
||||
make -j3
|
||||
|
||||
- name: Run RandomX tests
|
||||
run: |
|
||||
build/p2pool --test
|
||||
build/external/src/RandomX/randomx-tests
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_LIBS=ON
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-flto" -DCMAKE_CXX_FLAGS="-flto" -DSTATIC_LIBS=ON
|
||||
make -j3
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd tests/build
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.os }}
|
||||
name: p2pool-macos-11
|
||||
path: build/p2pool
|
||||
|
||||
build-macos-aarch64:
|
||||
|
||||
timeout-minutes: 20
|
||||
runs-on: macos-11
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-Os -target arm64-apple-macos-11" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j3
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -target arm64-apple-macos-11' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -target arm64-apple-macos-11' -DCMAKE_CXX_FLAGS='-Os -target arm64-apple-macos-11' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-target arm64-apple-macos-11" -DCMAKE_CXX_FLAGS="-target arm64-apple-macos-11" -DSTATIC_LIBS=ON -DWITH_LTO=OFF -DARCH_ID=aarch64
|
||||
make -j3
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-macos-11-aarch64
|
||||
path: build/p2pool
|
||||
|
||||
build-freebsd:
|
||||
@@ -377,38 +594,41 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Build p2pool
|
||||
uses: cross-platform-actions/action@v0.10.0
|
||||
uses: cross-platform-actions/action@v0.19.0
|
||||
with:
|
||||
operating_system: ${{ matrix.os.name }}
|
||||
architecture: ${{ matrix.os.architecture }}
|
||||
version: ${{ matrix.os.version }}
|
||||
shell: bash
|
||||
run: |
|
||||
sudo pkg install -y cmake autoconf automake libtool
|
||||
sudo pkg install -y cmake
|
||||
cd external/src/curl
|
||||
autoreconf -fi
|
||||
./configure CFLAGS='-Os' --without-ssl --without-hyper --without-zlib --without-brotli --without-zstd --without-default-ssl-backend --without-ca-bundle --without-ca-path --without-ca-fallback --without-libpsl --without-libgsasl --without-librtmp --without-winidn --without-libidn2 --without-nghttp2 --without-ngtcp2 --without-nghttp3 --without-quiche --without-msh3 --without-zsh-functions-dir --without-fish-functions-dir --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies --disable-socketpair --disable-doh --disable-dateparse --disable-netrc --disable-progress-meter --disable-dnsshuffle --disable-hsts --disable-alt-svc --disable-ares
|
||||
cmake . -DCMAKE_C_FLAGS="-Os -flto" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j2
|
||||
cd ../libuv
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
cd ../../libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DBUILD_TESTING=OFF
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os -flto' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j2
|
||||
cd ../../libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os' -DCMAKE_CXX_FLAGS='-Os' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os -flto' -DCMAKE_CXX_FLAGS='-Os -flto' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j2
|
||||
cd ../../../..
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_BINARY=ON
|
||||
cmake .. -DCMAKE_C_FLAGS='-flto' -DCMAKE_CXX_FLAGS='-flto' -DSTATIC_LIBS=ON
|
||||
make -j2
|
||||
./p2pool --test
|
||||
external/src/RandomX/randomx-tests
|
||||
cd ../tests
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSTATIC_LIBS=ON
|
||||
cmake .. -DCMAKE_C_FLAGS='-flto' -DCMAKE_CXX_FLAGS='-flto' -DSTATIC_LIBS=ON
|
||||
make -j2
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
@@ -437,7 +657,7 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Build p2pool
|
||||
uses: cross-platform-actions/action@v0.10.0
|
||||
uses: cross-platform-actions/action@v0.19.0
|
||||
with:
|
||||
operating_system: ${{ matrix.os.name }}
|
||||
architecture: ${{ matrix.os.architecture }}
|
||||
@@ -452,6 +672,7 @@ jobs:
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make -j2
|
||||
gunzip *.gz
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: clang-tidy
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
clang-tidy:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libuv1-dev libzmq3-dev libcurl4-openssl-dev
|
||||
|
||||
- name: Install clang
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
sudo apt-get install -y clang-tidy-17
|
||||
clang-tidy-17 --verify-config
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: cmake p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DDEV_CLANG_TIDY=ON
|
||||
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
cd src
|
||||
clang-tidy-17 *.cpp -p ../build -checks=-clang-diagnostic-undefined-internal -warnings-as-errors=* -header-filter=^[^\.]
|
||||
@@ -13,7 +13,13 @@ name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
schedule:
|
||||
- cron: '44 11 * * 0'
|
||||
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
name: cppcheck
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
schedule:
|
||||
- cron: '57 0 * * *'
|
||||
|
||||
jobs:
|
||||
cppcheck-ubuntu:
|
||||
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libuv1-dev libzmq3-dev libcurl4-openssl-dev
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -25,14 +40,27 @@ jobs:
|
||||
cd cppcheck-main
|
||||
make -j$(nproc) cppcheck
|
||||
|
||||
- name: cmake p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DSTATIC_LIBS=ON
|
||||
python ../cppcheck/remove_external.py compile_commands.json
|
||||
|
||||
- name: Run cppcheck
|
||||
run: |
|
||||
cd cppcheck
|
||||
./run.sh
|
||||
|
||||
- name: Archive full error list
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: errors_full-linux
|
||||
path: cppcheck/errors_full.txt
|
||||
|
||||
cppcheck-windows:
|
||||
|
||||
timeout-minutes: 20
|
||||
timeout-minutes: 60
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
@@ -59,9 +87,15 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 17 2022"
|
||||
cmake .. -G "Visual Studio 17 2022" -DSTATIC_LIBS=ON
|
||||
|
||||
- name: Run cppcheck
|
||||
run: |
|
||||
cd cppcheck
|
||||
./run.cmd
|
||||
|
||||
- name: Archive full error list
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: errors_full-windows
|
||||
path: cppcheck/errors_full.txt
|
||||
|
||||
@@ -10,7 +10,13 @@ name: Microsoft C++ Code Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
schedule:
|
||||
- cron: '40 10 * * 0'
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
name: source-snapshot
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
source-snapshot:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Compress source code
|
||||
run: |
|
||||
mkdir build
|
||||
XZ_OPT=-e9 tar --exclude=".git" --exclude="build" -f build/p2pool_source.tar.xz -c ../p2pool --xz
|
||||
|
||||
- name: Archive source code
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_source.tar.xz
|
||||
path: build/p2pool_source.tar.xz
|
||||
+320
-19
@@ -1,9 +1,173 @@
|
||||
name: Sync test
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docker-compose/**'
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
|
||||
pull_request:
|
||||
|
||||
schedule:
|
||||
- cron: '17 0/3 * * *'
|
||||
|
||||
jobs:
|
||||
sync-test-ubuntu:
|
||||
sync-test-ubuntu-tsan:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt update
|
||||
sudo apt install -y git build-essential cmake gcc-12 g++-12
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_C_FLAGS='-fsanitize=thread -Os -fno-omit-frame-pointer -g' -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_C_FLAGS='-fsanitize=thread -Os -fno-omit-frame-pointer -g' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_C_FLAGS='-fsanitize=thread -Os -fno-omit-frame-pointer -g' -DCMAKE_CXX_FLAGS='-fsanitize=thread -Os -fno-omit-frame-pointer -g' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DDEV_TEST_SYNC=ON -DDEV_WITH_TSAN=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DWITH_LTO=OFF -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- 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 &
|
||||
TSAN_OPTIONS="suppressions=../tests/src/tsan_sup.txt halt_on_error=1" ./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data_tsan
|
||||
path: |
|
||||
build/*.log
|
||||
build/data/
|
||||
|
||||
sync-test-ubuntu-msan:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y git build-essential cmake ninja-build
|
||||
|
||||
- name: Install clang
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Build libcxx_msan
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/llvm/llvm-project -b release/17.x
|
||||
cd llvm-project
|
||||
mkdir build
|
||||
cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DLLVM_USE_SANITIZER=MemoryWithOrigins
|
||||
ninja -C build cxx cxxabi
|
||||
cd build
|
||||
mkdir /tmp/libcxx_msan
|
||||
cp -r include /tmp/libcxx_msan
|
||||
cp -r lib /tmp/libcxx_msan
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_COMPILER=clang-17 -DCMAKE_C_FLAGS='-fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -Os -fno-omit-frame-pointer -g' -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j$(nproc)
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang-17 -DCMAKE_C_FLAGS='-fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -Os -fno-omit-frame-pointer -g' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_FLAGS='-fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -Os -fno-omit-frame-pointer -g' -DCMAKE_CXX_FLAGS='-nostdinc++ -nostdlib++ -fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -Os -fno-omit-frame-pointer -g -isystem /tmp/libcxx_msan/include/c++/v1 -L/tmp/libcxx_msan/lib -lc++ -lc++abi -Wno-unused-command-line-argument' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_C_FLAGS='-fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -fno-omit-frame-pointer -g' -DCMAKE_CXX_FLAGS='-nostdinc++ -nostdlib++ -fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -isystem /tmp/libcxx_msan/include/c++/v1 -L/tmp/libcxx_msan/lib -Wl,-rpath /tmp/libcxx_msan/lib -lc++ -lc++abi -Wno-unused-command-line-argument -fuse-ld=lld-17 -fno-omit-frame-pointer -g' -DDEV_TEST_SYNC=ON -DDEV_WITH_MSAN=ON -DSTATIC_LIBS=ON
|
||||
make -j$(nproc)
|
||||
|
||||
- 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 &
|
||||
MSAN_OPTIONS="halt_on_error=1" ./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data_msan
|
||||
path: |
|
||||
build/*.log
|
||||
build/data/
|
||||
|
||||
sync-test-ubuntu-ubsan:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -24,28 +188,81 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DDEV_TEST_SYNC=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12
|
||||
cmake .. -DDEV_TEST_SYNC=ON -DDEV_WITH_UBSAN=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_C_FLAGS="-flto=2" -DCMAKE_CXX_FLAGS="-flto=2"
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Run p2pool
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
cd build
|
||||
mkdir data
|
||||
./p2pool --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --data-api data --local-api --loglevel 6
|
||||
python ../tests/src/stratum_dummy.py 1 &
|
||||
python ../tests/src/stratum_dummy.py 2 &
|
||||
python ../tests/src/stratum_dummy.py 3 &
|
||||
UBSAN_OPTIONS="suppressions=../tests/src/ubsan_sup.txt halt_on_error=1" ./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data
|
||||
name: p2pool_ubuntu_data_ubsan
|
||||
path: |
|
||||
build/p2pool.log
|
||||
build/*.log
|
||||
build/data/
|
||||
|
||||
sync-test-ubuntu-asan:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt update
|
||||
sudo apt install -y git build-essential cmake libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev gcc-12 g++-12
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DDEV_TEST_SYNC=ON -DDEV_WITH_ASAN=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_C_FLAGS="-flto=2" -DCMAKE_CXX_FLAGS="-flto=2"
|
||||
make -j$(nproc)
|
||||
|
||||
- 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 &
|
||||
ASAN_OPTIONS="detect_stack_use_after_return=1 atexit=1" ./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data_asan
|
||||
path: |
|
||||
build/*.log
|
||||
build/data/
|
||||
|
||||
sync-test-macos:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: macos-12
|
||||
runs-on: macos-11
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -54,31 +271,63 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake libuv zmq libpgm curl
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install pyenv
|
||||
pyenv install 3:latest
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-Os -flto" -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DCURL_ZLIB=OFF -DCURL_DISABLE_ALTSVC=ON -DCURL_DISABLE_COOKIES=ON -DCURL_DISABLE_DOH=ON -DCURL_DISABLE_GETOPTIONS=ON -DCURL_DISABLE_HSTS=ON -DCURL_DISABLE_LIBCURL_OPTION=ON -DCURL_DISABLE_MIME=ON -DCURL_DISABLE_NETRC=ON -DCURL_DISABLE_NTLM=ON -DCURL_DISABLE_PARSEDATE=ON -DCURL_DISABLE_PROGRESS_METER=ON -DCURL_DISABLE_SHUFFLE_DNS=ON -DCURL_DISABLE_SOCKETPAIR=ON -DCURL_DISABLE_VERBOSE_STRINGS=ON -DHTTP_ONLY=ON -DCURL_ENABLE_SSL=OFF -DUSE_LIBIDN2=OFF -DCURL_USE_LIBPSL=OFF -DCURL_USE_LIBSSH2=OFF -DENABLE_UNIX_SOCKETS=OFF
|
||||
make -j3
|
||||
cd lib && mkdir .libs && cp libcurl.a .libs
|
||||
|
||||
- name: Build libuv
|
||||
run: |
|
||||
cd external/src/libuv
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -flto' -DBUILD_TESTING=OFF -DLIBUV_BUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS='-Os -flto' -DCMAKE_CXX_FLAGS='-Os -flto' -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DBUILD_SHARED=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DDEV_TEST_SYNC=ON
|
||||
cmake .. -DCMAKE_C_COMPILER="$(brew --prefix llvm@15)/bin/clang" -DCMAKE_CXX_COMPILER="$(brew --prefix llvm@15)/bin/clang++" -DCMAKE_AR="$(brew --prefix llvm@15)/bin/llvm-ar" -DCMAKE_RANLIB="$(brew --prefix llvm@15)/bin/llvm-ranlib" -DCMAKE_C_FLAGS="-flto" -DCMAKE_CXX_FLAGS="-flto" -DSTATIC_LIBS=ON -DDEV_TEST_SYNC=ON
|
||||
make -j3
|
||||
|
||||
- name: Run p2pool
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
cd build
|
||||
mkdir data
|
||||
./p2pool --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --data-api data --local-api --loglevel 6
|
||||
python3 ../tests/src/stratum_dummy.py 1 &
|
||||
python3 ../tests/src/stratum_dummy.py 2 &
|
||||
python3 ../tests/src/stratum_dummy.py 3 &
|
||||
./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_macos_data
|
||||
path: |
|
||||
build/p2pool.log
|
||||
build/*.log
|
||||
build/data/
|
||||
|
||||
sync-test-windows:
|
||||
sync-test-windows-debug-asan:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: windows-2022
|
||||
@@ -97,19 +346,71 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 17 2022" -DDEV_TEST_SYNC=ON
|
||||
& "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\msbuild" /m /p:Configuration=Debug p2pool.vcxproj
|
||||
& "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\msbuild" -v:m /m /p:Configuration=Debug p2pool.vcxproj
|
||||
|
||||
- name: Run p2pool
|
||||
timeout-minutes: 15
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsall.bat" amd64
|
||||
cd build/Debug
|
||||
mkdir data
|
||||
./p2pool.exe --host p2pmd.xmrvsbeast.com --zmq-port 18084 --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --no-cache --data-api data --local-api --loglevel 6
|
||||
start python ../../tests/src/stratum_dummy.py 1
|
||||
start python ../../tests/src/stratum_dummy.py 2
|
||||
start python ../../tests/src/stratum_dummy.py 3
|
||||
p2pool.exe --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build/Debug
|
||||
findstr /C:"Synchronization finished successfully" p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_windows_data
|
||||
name: p2pool_windows_data_debug_asan
|
||||
path: |
|
||||
build/Debug/p2pool.log
|
||||
build/Debug/*.log
|
||||
build/Debug/data/
|
||||
|
||||
sync-test-windows-leaks:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup cmake
|
||||
uses: lukka/get-cmake@latest
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 17 2022" -DDEV_TEST_SYNC=ON -DDEV_TRACK_MEMORY=ON
|
||||
& "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\msbuild" -v:m /m /p:Configuration=RelWithDebInfo p2pool.vcxproj
|
||||
|
||||
- name: Run p2pool
|
||||
run: |
|
||||
cd build/RelWithDebInfo
|
||||
mkdir data
|
||||
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 1"
|
||||
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 2"
|
||||
Start-Process python -ArgumentList "../../tests/src/stratum_dummy.py 3"
|
||||
./p2pool.exe --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --mini --out-peers 200 --data-api data --local-api --loglevel 6
|
||||
|
||||
- name: Check p2pool.log
|
||||
run: |
|
||||
cd build/RelWithDebInfo
|
||||
findstr /C:"Synchronization finished successfully" p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_windows_data_leaks
|
||||
path: |
|
||||
build/RelWithDebInfo/*.log
|
||||
build/RelWithDebInfo/data/
|
||||
|
||||
+127
-16
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(p2pool)
|
||||
|
||||
option(STATIC_BINARY "Build static binary" OFF)
|
||||
@@ -8,6 +8,12 @@ option(WITH_LTO "Use link-time compiler optimization (if linking fails for you,
|
||||
option(WITH_UPNP "Include UPnP support. If this is turned off, p2pool will not be able to configure port forwarding on UPnP-enabled routers." ON)
|
||||
|
||||
option(DEV_TEST_SYNC "[Developer only] Sync test, stop p2pool after sync is complete" OFF)
|
||||
option(DEV_WITH_TSAN "[Developer only] Compile with thread sanitizer" OFF)
|
||||
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_CLANG_TIDY "[Developer only] Compile for clang-tidy" OFF)
|
||||
option(DEV_TRACK_MEMORY "[Developer only] Track memory allocations" OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -31,6 +37,30 @@ if (DEV_TEST_SYNC)
|
||||
add_definitions(-DDEV_TEST_SYNC)
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_TSAN)
|
||||
add_definitions(-DDEV_WITH_TSAN)
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_MSAN)
|
||||
add_definitions(-DDEV_WITH_MSAN)
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_UBSAN)
|
||||
add_definitions(-DDEV_WITH_UBSAN)
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_ASAN)
|
||||
add_definitions(-DDEV_WITH_ASAN)
|
||||
endif()
|
||||
|
||||
if (DEV_CLANG_TIDY)
|
||||
add_definitions(-DDEV_CLANG_TIDY)
|
||||
endif()
|
||||
|
||||
if (DEV_TRACK_MEMORY)
|
||||
add_definitions(-DDEV_TRACK_MEMORY)
|
||||
endif()
|
||||
|
||||
include(cmake/flags.cmake)
|
||||
|
||||
set(HEADERS
|
||||
@@ -56,7 +86,6 @@ set(HEADERS
|
||||
src/side_chain.h
|
||||
src/stratum_server.h
|
||||
src/tcp_server.h
|
||||
src/tcp_server.inl
|
||||
src/util.h
|
||||
src/uv_util.h
|
||||
src/wallet.h
|
||||
@@ -85,6 +114,7 @@ set(SOURCES
|
||||
src/pow_hash.cpp
|
||||
src/side_chain.cpp
|
||||
src/stratum_server.cpp
|
||||
src/tcp_server.cpp
|
||||
src/util.cpp
|
||||
src/wallet.cpp
|
||||
src/zmq_reader.cpp
|
||||
@@ -95,7 +125,7 @@ if (WITH_RANDOMX)
|
||||
set(SOURCES ${SOURCES} src/miner.cpp)
|
||||
endif()
|
||||
|
||||
if (NOT STATIC_BINARY AND NOT STATIC_LIBS)
|
||||
if (NOT ((CMAKE_CXX_COMPILER_ID MATCHES MSVC) OR STATIC_BINARY OR STATIC_LIBS))
|
||||
include(FindCURL)
|
||||
endif()
|
||||
|
||||
@@ -129,11 +159,13 @@ if (WITH_UPNP)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi dnsapi dbghelp)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(LIBS ${LIBS} bcrypt)
|
||||
endif()
|
||||
add_definitions(-DCURL_STATICLIB)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
|
||||
set(LIBS ${LIBS} pthread)
|
||||
elseif (NOT APPLE)
|
||||
@@ -143,9 +175,9 @@ endif()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
find_library(ZMQ_LIBRARY_DEBUG NAMES libzmq-v142-mt-sgd-4_3_5 PATHS "external/lib/libzmq/Debug")
|
||||
find_library(ZMQ_LIBRARY NAMES libzmq-v142-mt-s-4_3_5 PATHS "external/lib/libzmq/Release")
|
||||
find_library(UV_LIBRARY_DEBUG NAMES uv_a PATHS "external/lib/libuv/Debug")
|
||||
find_library(UV_LIBRARY NAMES uv_a PATHS "external/lib/libuv/Release")
|
||||
find_library(CURL_LIBRARY_DEBUG NAMES libcurld PATHS "external/lib/libcurl/Debug")
|
||||
find_library(UV_LIBRARY_DEBUG NAMES libuv PATHS "external/lib/libuv/Debug")
|
||||
find_library(UV_LIBRARY NAMES libuv PATHS "external/lib/libuv/Release")
|
||||
find_library(CURL_LIBRARY_DEBUG NAMES libcurl-d PATHS "external/lib/libcurl/Debug")
|
||||
find_library(CURL_LIBRARY NAMES libcurl PATHS "external/lib/libcurl/Release")
|
||||
add_definitions(-D_DISABLE_VECTOR_ANNOTATION)
|
||||
add_definitions(-D_DISABLE_STRING_ANNOTATION)
|
||||
@@ -193,14 +225,69 @@ endif()
|
||||
|
||||
add_definitions(/DZMQ_STATIC)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${GENERAL_FLAGS}")
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
check_cxx_source_compiles("int main(){ return __builtin_clzll(1);}" HAVE_BUILTIN_CLZLL)
|
||||
check_cxx_source_compiles("#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\nint main(){unsigned long r;_BitScanReverse64(&r,1);return r;}" HAVE_BITSCANREVERSE64)
|
||||
check_cxx_source_compiles("#include <sched.h>\nint main(){sched_param param;return sched_setscheduler(0, SCHED_IDLE, ¶m);}" HAVE_SCHED)
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES "resolv")
|
||||
|
||||
check_c_source_compiles("int main() { return 0; }" HAVE_RESOLV_LIB)
|
||||
|
||||
if (NOT HAVE_RESOLV_LIB)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
res_init();
|
||||
|
||||
uint8_t answer[4096];
|
||||
const int anslen = res_query(argv[1], ns_c_in, ns_t_txt, answer, sizeof(answer));
|
||||
|
||||
if (anslen > (int) sizeof(answer)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ns_msg handle;
|
||||
ns_initparse(answer, anslen, &handle);
|
||||
|
||||
for (int rrnum = 0, n = ns_msg_count(handle, ns_s_an); rrnum < n; ++rrnum) {
|
||||
ns_rr rr;
|
||||
if ((ns_parserr(&handle, ns_s_an, rrnum, &rr) == 0) && (ns_rr_type(rr) == ns_t_txt)) {
|
||||
for (const uint8_t* data = ns_rr_rdata(rr), *e = data + ns_rr_rdlen(rr); data < e;) {
|
||||
const int k = *(data++);
|
||||
if (k && (data + k <= e)) {
|
||||
char buf[256];
|
||||
memcpy(buf, data, k);
|
||||
buf[k] = 0;
|
||||
puts(buf);
|
||||
}
|
||||
data += k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}" HAVE_RES_QUERY)
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
if (HAVE_BUILTIN_CLZLL)
|
||||
add_definitions(/DHAVE_BUILTIN_CLZLL)
|
||||
endif()
|
||||
@@ -213,15 +300,28 @@ if (HAVE_SCHED)
|
||||
add_definitions(/DHAVE_SCHED)
|
||||
endif()
|
||||
|
||||
if (HAVE_RES_QUERY)
|
||||
add_definitions(/DHAVE_RES_QUERY)
|
||||
if (HAVE_RESOLV_LIB)
|
||||
set(LIBS ${LIBS} resolv)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_definitions("-DRAPIDJSON_PARSE_DEFAULT_FLAGS=kParseTrailingCommasFlag")
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
|
||||
if (STATIC_BINARY OR STATIC_LIBS)
|
||||
if (WIN32)
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} "${CMAKE_PROJECT_NAME}.exe")
|
||||
else()
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} ${CMAKE_PROJECT_NAME})
|
||||
if (NOT (DEV_WITH_TSAN OR DEV_WITH_MSAN OR DEV_WITH_UBSAN OR DEV_WITH_ASAN))
|
||||
if (WIN32)
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} "${CMAKE_PROJECT_NAME}.exe")
|
||||
else()
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} ${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(STATIC_LIBS "")
|
||||
|
||||
if (WITH_RANDOMX)
|
||||
set(STATIC_LIBS randomx)
|
||||
endif()
|
||||
@@ -231,8 +331,8 @@ if (STATIC_BINARY OR STATIC_LIBS)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} ws2_32 iphlpapi userenv psapi wldap32)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} ws2_32 iphlpapi userenv psapi dnsapi dbghelp)
|
||||
if ((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
|
||||
set(STATIC_LIBS ${STATIC_LIBS} bcrypt)
|
||||
endif()
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
|
||||
@@ -246,12 +346,23 @@ if (STATIC_BINARY OR STATIC_LIBS)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} pthread)
|
||||
endif()
|
||||
|
||||
if (HAVE_RES_QUERY AND HAVE_RESOLV_LIB)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} resolv)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
"${CMAKE_SOURCE_DIR}/external/src/libzmq/build/lib/libzmq.a"
|
||||
"${CMAKE_SOURCE_DIR}/external/src/libuv/build/libuv_a.a"
|
||||
"${CMAKE_SOURCE_DIR}/external/src/libuv/build/libuv.a"
|
||||
"${CMAKE_SOURCE_DIR}/external/src/curl/lib/.libs/libcurl.a"
|
||||
${STATIC_LIBS}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} debug ${CURL_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} optimized ${CURL_LIBRARY} ${LIBS})
|
||||
endif()
|
||||
|
||||
message(STATUS "Summary of build options:
|
||||
C compiler: ${CMAKE_C_COMPILER} (${CMAKE_C_COMPILER_ID})
|
||||
CXX compiler: ${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_ID})
|
||||
C_FLAGS: ${CMAKE_C_FLAGS}
|
||||
CXX_FLAGS: ${CMAKE_CXX_FLAGS}
|
||||
")
|
||||
|
||||
@@ -4,11 +4,7 @@ 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/
|
||||
|
||||
# P2Pool hardfork on March 18, 2023
|
||||
|
||||
P2Pool (not Monero!) will hardfork to new consensus rules on March 18th at 21:00 UTC (use [this link](https://dateful.com/convert/utc?t=9pm&d=2023-03-18) to convert to your local time). The hardfork is necessary to improve P2Pool scalability and reduce the impact on Monero blockchain. You'll need to update to **P2Pool v3.0** or newer version before this time.
|
||||
|
||||
Reddit discussion: https://www.reddit.com/r/MoneroMining/comments/1095730/psa_p2pool_network_upgrade_aka_hardfork_on_march/
|
||||
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.
|
||||
|
||||
### Build Status
|
||||
|
||||
@@ -22,10 +18,11 @@ Reddit discussion: https://www.reddit.com/r/MoneroMining/comments/1095730/psa_p2
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://scan.coverity.com/projects/23659/badge.svg"/>
|
||||
</a>
|
||||

|
||||
# Contents
|
||||
- [Pool mining vs Solo mining vs P2Pool mining](#pool-mining-vs-solo-mining-vs-p2pool-mining)
|
||||
- [Features](#features)
|
||||
- [How PPLNS works in P2Pool](#how-pplns-works-in-p2pool)
|
||||
- [How payouts work in P2Pool](#how-payouts-work-in-p2pool)
|
||||
- [Default P2Pool parameters](#default-p2pool-parameters)
|
||||
- [Monero version support](#monero-version-support)
|
||||
- [How to mine on P2Pool](#how-to-mine-on-p2pool)
|
||||
@@ -44,42 +41,46 @@ 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%|~0.0003 XMR|No|As stable as your Monero node|100% under your control|Monero node + P2Pool node + miner
|
||||
|**P2Pool**|Regular|0%|~0.00027 XMR|No|Very stable: node failover and multiple Monero nodes are supported|100% under your control|Monero node(s) + P2Pool node(s) + optional miner(s)
|
||||
|
||||
## Features
|
||||
|
||||
* Decentralized: no central server that can be shutdown/blocked. P2Pool uses a separate blockchain to merge mine with Monero. Pool admin can't go rogue or be pressured to do an attack on the network because there is no pool admin!
|
||||
* Permissionless: there is no one to decide who can mine on the pool and who can't.
|
||||
* Trustless: there is no pool wallet, funds are never in custody. All pool blocks pay out to miners immediately.
|
||||
* Trustless: there is no pool wallet, funds are never in custody. All pool blocks pay out to miners directly.
|
||||
* PPLNS payout scheme
|
||||
* **0% fee**
|
||||
* **0 XMR payout fee**
|
||||
* **~0.0003 XMR minimal payout**
|
||||
* **~0.00027 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
|
||||
* Advanced mempool picking algorithm, it creates blocks with better reward than what monerod solo mining does
|
||||
* Password protected private pools
|
||||
* Highly reliable configurations are supported (multiple P2Pool nodes mining to the same wallet, each P2Pool node can use multiple Monero nodes and switch on the fly if an issue is detected)
|
||||
|
||||
## How PPLNS works in P2Pool
|
||||
## How payouts work in P2Pool
|
||||
|
||||
First you need to find a pool share. This share will stay in PPLNS window for 2160 pool blocks (6 hours). The moment P2Pool finds a Monero block and you have at least 1 pool share in PPLNS window, you'll get a payout! Monero block reward is split between all miner wallets in PPLNS window. Each miner gets a part of block reward proportional to the total difficulty of his/her shares in PPLNS window.
|
||||
First you need to find a pool share. This share will stay in [PPLNS](https://en.wikipedia.org/wiki/Mining_pool#Pay-per-last-N-shares) window for up to 2160 pool blocks (6 hours, auto adjustable to balance payout sizes and frequency). The moment P2Pool finds a Monero block and you have at least 1 pool share in PPLNS window, you'll get a payout! Monero block reward is split between all miner wallets in PPLNS window. Each miner gets a part of block reward proportional to the total difficulty of his/her shares in PPLNS window.
|
||||
|
||||
**NOTE** If P2Pool doesn't have enough hashrate to find Monero blocks faster than every 6 hours on average (~15 MH/s), **not all your pool shares will result in a payout**. Even if pool hashrate is higher, bad luck can sometimes result in a share going through PPLNS window without a payout. But in the long run it will be compensated by other shares receiving multiple payouts - your payouts will average out to what you'd get with regular pool mining.
|
||||
|
||||
## Default P2Pool parameters
|
||||
|
||||
* Block time: 10 seconds
|
||||
* PPLNS window: 2160 blocks (6 hours)
|
||||
* Minimum payout = Monero block reward/2160, ~0.0003 XMR
|
||||
* PPLNS window: up to 2160 blocks (6 hours, auto adjustable to balance payout sizes and frequency)
|
||||
* Minimum payout = Monero block reward/2160, ~0.00027 XMR
|
||||
|
||||
## Monero version support
|
||||
|
||||
Monero network upgrade happened on August 13th, 2022 (block 2,688,888). In order to continue mining, you must update both Monero and P2Pool software to the latest available versions as soon as they are released.
|
||||
- The latest Monero network upgrade happened on August 13th, 2022 (block 2,688,888).
|
||||
- The latest P2Pool network upgrade happened on March 18th, 2023 at 21:00 UTC.
|
||||
|
||||
In order to continue mining on P2Pool, you must update both Monero and P2Pool software to the latest available versions as soon as they are released.
|
||||
|
||||
|Monero protocol version|Required Monero software version|Required P2Pool version
|
||||
|-|-|-|
|
||||
|v15, v16 (active after August 13th, 2022)|v0.18.0.0 or newer|v2.2 or newer
|
||||
|v15, v16 (active after August 13th, 2022)|v0.18.0.0 or newer, v0.18.3.1 is recommended|v3.0 or newer
|
||||
|
||||
## How to mine on P2Pool
|
||||
|
||||
@@ -87,7 +88,7 @@ Monero network upgrade happened on August 13th, 2022 (block 2,688,888). In order
|
||||
|
||||
- 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, 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 have to use a primary wallet address for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
|
||||
- You have to use a primary wallet address (the one starting with `4`) for mining. Subaddresses and integrated addresses are not supported, just like with monerod solo mining.
|
||||
- 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 connect multiple miners to the same P2Pool node. The more the better!
|
||||
@@ -111,21 +112,21 @@ Monero network upgrade happened on August 13th, 2022 (block 2,688,888). In order
|
||||
1. Download the latest P2Pool binaries [here](https://github.com/SChernykh/p2pool/releases/latest).
|
||||
- Alternatively, grab the latest source code for P2Pool and [build it](#build-instructions).
|
||||
2. Download the latest XMRig (linux-static-x64) binary [here](https://github.com/xmrig/xmrig/releases/latest).
|
||||
3. Prepare enough huge pages (required for each instance of monerod/P2Pool/XMRig):
|
||||
3. Prepare enough huge pages (each of monerod/P2Pool/XMRig needs them):
|
||||
```
|
||||
sudo sysctl vm.nr_hugepages=3072
|
||||
```
|
||||
4. Check that ports 18080 (Monero p2p port) and 37889/37888 (P2Pool/P2Pool mini p2p port) are open in your local firewall to ensure better connectivity.
|
||||
5. Start `monerod` with the following command/options:
|
||||
```
|
||||
./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 64 --in-peers 32 --add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
```
|
||||
**Note:**
|
||||
The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
|
||||
`--out-peers 64 --in-peers 32` is needed to (1) have many connections to other nodes and (2) limit incoming connection count because it can grow uncontrollably and cause problems when it goes above 1000 (open files limit in Linux). If your network connection's **upload** bandwidth is less than **10 Mbit**, use `--out-peers 16 --in-peers 8` instead.
|
||||
`--out-peers 32 --in-peers 64` is needed to (1) have many connections to other nodes and (2) limit incoming connection count because it can grow uncontrollably and cause problems when it goes above 1000 (open files limit in Linux). If your network connection's **upload** bandwidth is less than **10 Mbit**, use `--out-peers 8 --in-peers 16` instead.
|
||||
|
||||
`--add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
`--add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
|
||||
`--disable-dns-checkpoints` is needed to avoid periodical lags when DNS is updated (it's not needed when mining)
|
||||
|
||||
@@ -176,7 +177,7 @@ nocreate
|
||||
2. Download the latest XMRig binary [here](https://github.com/xmrig/xmrig/releases/latest).
|
||||
3. Expand the P2Pool binaries into an appropriate location (`%USERPROFILE%/bin` or `C:/bin/` are good options)
|
||||
4. Expand XMRig binary into an appropriate location (the same folder as P2Pool is fine).
|
||||
5. Prepare huge pages to work properly (each instance of monerod/P2Pool/XMRig needs them):
|
||||
5. Prepare huge pages to work properly (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 XMRig as Administrator at least once per login.
|
||||
6. Create "Monero" folder inside extracted P2Pool folder and copy Monero binaries there.
|
||||
@@ -186,14 +187,14 @@ nocreate
|
||||
|
||||
8. Start `monerod` with the following command/options:
|
||||
```
|
||||
.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 64 --in-peers 32 --add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
.\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
```
|
||||
**Note:**
|
||||
The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
|
||||
`--out-peers 64 --in-peers 32` is needed to (1) have many connections to other nodes and (2) limit incoming connection count because it can grow uncontrollably and cause problems when it goes above 1000 (open files limit in Linux). If your network connection's **upload** bandwidth is less than **10 Mbit**, use `--out-peers 16 --in-peers 8` instead.
|
||||
`--out-peers 32 --in-peers 64` is needed to (1) have many connections to other nodes and (2) limit incoming connection count because it can grow uncontrollably and cause problems when it goes above 1000 (open files limit in Linux). If your network connection's **upload** bandwidth is less than **10 Mbit**, use `--out-peers 8 --in-peers 16` instead.
|
||||
|
||||
`--add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
`--add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080` is needed to have guaranteed good working nodes in your connected peers.
|
||||
|
||||
`--disable-dns-checkpoints` is needed to avoid periodical lags when DNS is updated (it's not needed when mining)
|
||||
|
||||
@@ -217,7 +218,7 @@ The `--zmq-pub` option is required for P2Pool to work properly.
|
||||
13. *(Optional but highly recommended)* You can create a Quickstart by creating a batch (.bat) file with the following contents and placing it in your P2Pool directory along with `xmrig.exe`.
|
||||
```
|
||||
@ECHO OFF
|
||||
start cmd /k %~dp0\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 64 --in-peers 32 --add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist
|
||||
start cmd /k %~dp0\Monero\monerod.exe --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --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 --mini
|
||||
@@ -227,6 +228,8 @@ PAUSE
|
||||
```
|
||||
|
||||
## Build instructions
|
||||
Only 64-bit builds are supported, in particular ARMv7 or older CPUs are not supported. The reason is that RandomX hashing algorithm is too slow in 32-bit mode, and P2Pool needs to check new blocks very fast to keep up with other nodes.
|
||||
|
||||
Please see the relevant instructions for your platform:
|
||||
|
||||
### Ubuntu 20.04
|
||||
@@ -241,7 +244,7 @@ cmake ..
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
### [Arch Linux](https://archlinux.org/packages/community/x86_64/p2pool/)
|
||||
### [Arch Linux](https://archlinux.org/packages/extra/x86_64/p2pool/)
|
||||
|
||||
```
|
||||
pacman -S p2pool
|
||||
|
||||
+53
-5
@@ -5,10 +5,43 @@ set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT ARCH_ID)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "")
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH_ID)
|
||||
endif()
|
||||
|
||||
if (ARCH_ID MATCHES "^(aarch64|arm64|armv8-a)$")
|
||||
set(ARMv8 1)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wcast-align -Wcast-qual -Wlogical-op -Wstrict-overflow=2 -Wundef -Wformat=2 -Wpointer-arith -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
|
||||
if (ARMv8)
|
||||
set(GENERAL_FLAGS "${GENERAL_FLAGS} -mfix-cortex-a53-835769 -mfix-cortex-a53-843419")
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_TSAN)
|
||||
set(GENERAL_FLAGS "${GENERAL_FLAGS} -fno-omit-frame-pointer -fsanitize=thread")
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_UBSAN)
|
||||
set(GENERAL_FLAGS "${GENERAL_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined")
|
||||
endif()
|
||||
|
||||
if (DEV_WITH_ASAN)
|
||||
set(GENERAL_FLAGS "${GENERAL_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
|
||||
endif()
|
||||
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wcast-qual -Wlogical-op -Wstrict-overflow=2 -Wundef -Wformat=2 -Wpointer-arith -Werror")
|
||||
|
||||
if (DEV_WITH_TSAN OR DEV_WITH_UBSAN OR DEV_WITH_ASAN)
|
||||
set(OPTIMIZATION_FLAGS "-O2 -g")
|
||||
else()
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
endif()
|
||||
|
||||
if (WITH_LTO)
|
||||
set(OPTIMIZATION_FLAGS "${OPTIMIZATION_FLAGS} -flto -fuse-linker-plugin")
|
||||
@@ -34,7 +67,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
endif()
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(GENERAL_FLAGS "/MP")
|
||||
set(GENERAL_FLAGS "/MP /EHa")
|
||||
set(WARNING_FLAGS "/Wall /WX /sdl")
|
||||
set(SECURITY_FLAGS "/GS /guard:cf")
|
||||
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
|
||||
@@ -50,9 +83,24 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
if (WIN32)
|
||||
set(GENERAL_FLAGS "")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
else()
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
endif()
|
||||
|
||||
if (ARMv8)
|
||||
set(GENERAL_FLAGS "${GENERAL_FLAGS} -mfix-cortex-a53-835769")
|
||||
endif()
|
||||
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal -Wunreachable-code-aggressive -Wmissing-prototypes -Wmissing-variable-declarations -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
|
||||
|
||||
if (DEV_WITH_MSAN)
|
||||
set(OPTIMIZATION_FLAGS "-O2 -g")
|
||||
else()
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
|
||||
endif()
|
||||
|
||||
if (WITH_LTO)
|
||||
set(OPTIMIZATION_FLAGS "${OPTIMIZATION_FLAGS} -flto")
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
../src/
|
||||
../external/src/
|
||||
../external/src/cryptonote/
|
||||
../external/src/libuv/include/
|
||||
../external/src/cppzmq/
|
||||
../external/src/libzmq/include/
|
||||
../external/src/curl/include
|
||||
../external/src/RandomX/src/
|
||||
../external/src/rapidjson/include
|
||||
../external/src/robin-hood-hashing/src/include
|
||||
@@ -0,0 +1,15 @@
|
||||
import sys
|
||||
import json
|
||||
|
||||
f = open(sys.argv[1])
|
||||
data = json.load(f)
|
||||
f.close()
|
||||
|
||||
v = []
|
||||
for el in data:
|
||||
if not ("/external/" in el['file']):
|
||||
v.append(el)
|
||||
|
||||
f = open(sys.argv[1], 'w')
|
||||
json.dump(v, f, indent=2)
|
||||
f.close()
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
"..\cppcheck-main\bin\cppcheck.exe" --project=..\build\p2pool.vcxproj --project-configuration="Release|x64" -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN --platform=win64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt
|
||||
"..\cppcheck-main\bin\cppcheck.exe" --project=..\build\p2pool.vcxproj --project-configuration="Release|x64" -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN --platform=win64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --suppressions-list=suppressions.txt --output-file=errors_full.txt --max-ctu-depth=3 --check-level=exhaustive
|
||||
findstr /V /C:"external\src" errors_full.txt > errors_filtered.txt
|
||||
for /f %%i in ("errors_filtered.txt") do set size=%%~zi
|
||||
if %size% gtr 0 (
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
../cppcheck-main/cppcheck ../src -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --includes-file=includes.txt --suppressions-list=suppressions.txt --output-file=errors_full.txt
|
||||
../cppcheck-main/cppcheck --project=../build/compile_commands.json -DSIZE_MAX=UINT64_MAX -DRAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN -D__SSE2__=1 --platform=unix64 --std=c++14 --enable=all --inconclusive --inline-suppr --template="{file}:{line}:{id}{inconclusive: INCONCLUSIVE} {message}" --suppressions-list=suppressions.txt --output-file=errors_full.txt --max-ctu-depth=3 --check-level=exhaustive
|
||||
grep -v 'external' errors_full.txt > errors_filtered.txt
|
||||
if [ -s errors_filtered.txt ]; then
|
||||
cat errors_filtered.txt
|
||||
|
||||
@@ -111,7 +111,7 @@ class MoneroHelpBox(HelpBoxBase):
|
||||
],
|
||||
"Expose RPC Port": [
|
||||
"Expose restricted RPC API port to your network so external services",
|
||||
"(wallets for example) can connect",
|
||||
"(wallets for example) can connect. Port 18083 (ZMQ-pub) will also be exposed.",
|
||||
"Note: You may choose to open this port in your hosts firewall and/or",
|
||||
" router to allow services outside your network to connect",
|
||||
],
|
||||
@@ -620,7 +620,7 @@ class MoneroConfigForm(ConfigFormBase):
|
||||
self.fast_sync = self.add(
|
||||
npyscreen.Checkbox,
|
||||
name="Fast Block Sync",
|
||||
value=False,
|
||||
value=True,
|
||||
begin_entry_at=self.name_size,
|
||||
relx=self.indent,
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"fast_sync": false,
|
||||
"fast_sync": true,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
"monero_node_login": "",
|
||||
|
||||
@@ -109,6 +109,7 @@ services:
|
||||
- 18080:18080/tcp
|
||||
{% if expose_rpc_port == True %}
|
||||
- {{ rpc_port }}:18081/tcp
|
||||
- 18083:18083/tcp
|
||||
{% endif %}
|
||||
volumes:
|
||||
- monero:/home/monero/.bitmonero:rw
|
||||
@@ -119,10 +120,10 @@ services:
|
||||
--zmq-pub tcp://0.0.0.0:18083
|
||||
--disable-dns-checkpoints
|
||||
--enable-dns-blocklist
|
||||
--out-peers 32
|
||||
--in-peers 16
|
||||
--out-peers 16
|
||||
--in-peers 32
|
||||
--add-priority-node=nodes.hashvault.pro:18080
|
||||
--add-priority-node=node.supportxmr.com:18080
|
||||
--add-priority-node=p2pmd.xmrvsbeast.com:18080
|
||||
--non-interactive
|
||||
--p2p-bind-ip=0.0.0.0
|
||||
--p2p-bind-port=18080
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"rate_limit_up": "2048",
|
||||
"rate_limit_down": "8192",
|
||||
"sync_pruned_blocks": false,
|
||||
"fast_sync": false,
|
||||
"fast_sync": true,
|
||||
"monero_options": "",
|
||||
"public_monero_node": "",
|
||||
"monero_node_login": "",
|
||||
|
||||
@@ -96,10 +96,10 @@ services:
|
||||
--zmq-pub tcp://0.0.0.0:18083
|
||||
--disable-dns-checkpoints
|
||||
--enable-dns-blocklist
|
||||
--out-peers 32
|
||||
--in-peers 16
|
||||
--out-peers 16
|
||||
--in-peers 32
|
||||
--add-priority-node=nodes.hashvault.pro:18080
|
||||
--add-priority-node=node.supportxmr.com:18080
|
||||
--add-priority-node=p2pmd.xmrvsbeast.com:18080
|
||||
--non-interactive
|
||||
--p2p-bind-ip=0.0.0.0
|
||||
--p2p-bind-port=18080
|
||||
@@ -115,7 +115,7 @@ services:
|
||||
|
||||
|
||||
|
||||
--fast-block-sync=0
|
||||
--fast-block-sync=1
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ def render():
|
||||
pool_stats = json.loads(reader.read())
|
||||
with open("/data/network/stats", "r") as reader:
|
||||
network_stats = json.loads(reader.read())
|
||||
with open("/data/local/stats", "r") as reader:
|
||||
with open("/data/local/stratum", "r") as reader:
|
||||
local_stats = json.loads(reader.read())
|
||||
return render_template(
|
||||
"index.html",
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
<td>Shares Found</td>
|
||||
<td>{{ local_stats["shares_found"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shares Failed</td>
|
||||
<td>{{ local_stats["shares_failed"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Effort</td>
|
||||
<td>{{ local_stats["current_effort"] }}%</td>
|
||||
@@ -56,6 +60,10 @@
|
||||
<td>Miner Connections</td>
|
||||
<td>{{ local_stats["incoming_connections"] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Block reward share</td>
|
||||
<td>{{ local_stats["block_reward_share_percent"] }}%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -29,8 +29,24 @@
|
||||
--no-upnp Disable UPnP port forwarding
|
||||
--no-igd An alias for --no-upnp
|
||||
--upnp-stratum Port forward Stratum port (it's not forwarded by default)
|
||||
--version Print p2pool's version and build details
|
||||
```
|
||||
|
||||
### Example command line
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
### Multiple backup hosts
|
||||
|
||||
You can have multiple hosts in command line. If P2Pool detects that the host it's currently using is down or stuck, it will cycle through hosts until it finds a working one. It will not switch back as long as the current host it found is working.
|
||||
|
||||
Each new host uses RPC and zmq-pub port numbers from the previous host (or default 18081/18083 if none were specified). Note that `--rpc-login` is not copied from the previous host, you must specify it for each host that has username/password.
|
||||
|
||||
In this example, you have local Monero host running on ports 18081/18083 (RPC/zmq-pub), and several backup hosts running on ports 18089/18084.
|
||||
|
||||
|
||||
```
|
||||
p2pool.exe --host 127.0.0.1 --host xmr1.rs.me --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --host xmr3.rs.me --wallet YOUR_WALLET_ADDRESS
|
||||
```
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
### P2Pool console commands
|
||||
|
||||
Command|Description
|
||||
-|-
|
||||
help|display list of commands
|
||||
status|display p2pool status
|
||||
loglevel **N**|set log level (**N** can be between 0 and 6)
|
||||
addpeers **L**|**L** is a comma-separated list of IP:port of other p2pool nodes to connect to
|
||||
droppeers|disconnect all currently connected peers
|
||||
peers|show all currently connected peers (p2p)
|
||||
workers|show all currently connected workers (stratum)
|
||||
bans|show all banned IPs
|
||||
hosts|show Monero hosts which were configured in the command line
|
||||
next_host|switch to the next Monero host configured in the command line
|
||||
outpeers **N**|set maximum number of outgoing connections (values above 50 are not recommended)
|
||||
inpeers **N**|set maximum number of incoming connections (values above 50 are not recommended)
|
||||
start_mining **T**|start mining (**T** is the number of threads to use, must be between 1 and 64)
|
||||
stop_mining|stop mining
|
||||
exit|terminate p2pool
|
||||
version|show p2pool version
|
||||
@@ -0,0 +1,49 @@
|
||||
## Setting up P2Pool as a systemd service (Linux)
|
||||
|
||||
With this config, P2Pool will run as a service with redirected I/O. It uses `p2pool` user which you should setup beforehand.
|
||||
|
||||
You can execute console commands by running `echo "status" > /run/p2pool/p2pool.control`
|
||||
|
||||
### p2pool.service
|
||||
```
|
||||
[Unit]
|
||||
Description=p2pool daemon
|
||||
After=network-online.target systemd-modules-load.service monerod.service
|
||||
Wants=network-online.target systemd-modules-load.service monerod.service
|
||||
Requires=p2pool.socket
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
Sockets=p2pool.socket
|
||||
StandardInput=socket
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
# /usr/local/bin/p2pool.sh simply invokes the p2pool executable with your chosen command-line options.
|
||||
ExecStart=/usr/local/bin/p2pool.sh
|
||||
TimeoutStopSec=60
|
||||
|
||||
# Run as p2pool:p2pool
|
||||
User=p2pool
|
||||
Group=p2pool
|
||||
|
||||
WorkingDirectory=/var/lib/p2pool
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### p2pool.socket
|
||||
```
|
||||
# FIFO socket for controlling p2pool daemon
|
||||
[Unit]
|
||||
Description=Command FIFO for p2pool daemon
|
||||
|
||||
[Socket]
|
||||
ListenFIFO=/run/p2pool/p2pool.control
|
||||
DirectoryMode=0755
|
||||
SocketMode=0666
|
||||
SocketUser=p2pool
|
||||
SocketGroup=p2pool
|
||||
RemoveOnStop=true
|
||||
```
|
||||
+15
-3
@@ -80,13 +80,22 @@ async function load_data() {
|
||||
let pool_stats_req = await fetch('api/pool/stats');
|
||||
let pool_blocks_req = await fetch('api/pool/blocks');
|
||||
let network_stats_req = await fetch('api/network/stats');
|
||||
let latest_release_req = await fetch('api/latest_release');
|
||||
|
||||
let pool_stats = JSON.parse(await pool_stats_req.text());
|
||||
let pool_blocks = JSON.parse(await pool_blocks_req.text());
|
||||
let network_stats = JSON.parse(await network_stats_req.text());
|
||||
let latest_release = JSON.parse(await latest_release_req.text());
|
||||
|
||||
let pool_hashrate = pool_stats.pool_statistics.hashRate / 1e6;
|
||||
let pplns_duration = pool_stats.pool_statistics.pplnsWeight / pool_stats.pool_statistics.hashRate;
|
||||
let min_payout = 0.6 * pool_stats.pool_statistics.sidechainDifficulty / pool_stats.pool_statistics.pplnsWeight;
|
||||
|
||||
document.getElementById("pool_hashrate").innerHTML = pool_hashrate.toFixed(3) + ' MH/s';
|
||||
document.getElementById("pplns_duration").innerHTML = elapsedTimeStr(0, pplns_duration, 0) + ' ' + Math.floor(pplns_duration % 60) + 's';
|
||||
document.getElementById("pool_miners").innerHTML = pool_stats.pool_statistics.miners;
|
||||
document.getElementById("min_payout").innerHTML = min_payout.toFixed(5) + ' XMR';
|
||||
document.getElementById("latest_release").innerHTML = '<a href="' + latest_release.html_url + '" target="_blank">' + latest_release.name + '</a>';
|
||||
|
||||
let ts = Math.floor(Date.now() / 1000);
|
||||
|
||||
@@ -185,6 +194,7 @@ function toggle_menu(name) {
|
||||
</head>
|
||||
<body onload="load_data();setInterval(load_data, 2000);toggle_menu(window.location.hash.substr(1));">
|
||||
<div style="font-size:3rem;text-align:center;">P2Pool</div><div style="font-size:1.1rem;text-align:center;">Decentralized Monero mining pool</div>
|
||||
<div style="font-size:1rem;text-align:center;">Latest release: <span id="latest_release"><a href="https://github.com/SChernykh/p2pool/releases/latest" target="_blank">P2Pool</a></span></div>
|
||||
<br>
|
||||
<table id="main_menu" style="width:100%;margin-left:auto;margin-right:auto;table-layout:fixed;text-align:center;-ms-touch-action:none;touch-action:none;"><tr>
|
||||
<td onclick="toggle_menu('pool')" id="button_pool">Pool</td>
|
||||
@@ -198,13 +208,14 @@ function toggle_menu(name) {
|
||||
<tr><td style="padding-bottom: 1rem;"></td><td></td><td></td></tr>
|
||||
<tr><td>Hashrate</td><td><span id="pool_hashrate">N/A</span></td><td><span id="monero_hashrate">N/A</span></td></tr>
|
||||
<tr><td>Miners</td><td><span id="pool_miners">N/A</span></td><td></td></tr>
|
||||
<tr><td>PPLNS window</td><td><span id="pplns_duration">N/A</span></td><td></td></tr>
|
||||
<tr><td>Last block</td><td><span id="pool_last_block">N/A</span></td><td><span id="monero_last_block">N/A</span></td></tr>
|
||||
<tr><td>Total blocks</td><td><span id="pool_total_blocks">N/A</span></td><td></td></tr>
|
||||
<tr><td>Current effort</td><td><span id="current_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td>Average effort<br><div style="text-align:center;font-size:0.9rem">last 50 blocks</div></td><td><span id="average_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Fee</td><td>0%</td><td></td></tr>
|
||||
<tr><td>Min payout</td><td>0.0003 XMR</td><td></td></tr>
|
||||
<tr><td>Min payout</td><td><span id="min_payout">0.00027 XMR</span></td><td></td></tr>
|
||||
<tr><td>Payout scheme</td><td><a href="https://en.wikipedia.org/wiki/Mining_pool#Pay-per-last-N-shares" target="_blank">PPLNS</a></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Statistics</td><td><a href="https://p2pool.observer/" target="_blank">P2Pool observer</a></td><td></td></tr>
|
||||
@@ -237,8 +248,8 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<ul>
|
||||
<li>Download the latest Monero <a href="https://www.getmonero.org/downloads/" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>18080</span> (Monero p2p port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 64 --in-peers 32 --add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 16 --in-peers 8</span> instead.
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 8 --in-peers 16</span> instead.
|
||||
<li>Wait until it's fully synchronized. If you didn't run Monero node before, it can take up to several days to synchronize (5-6 hours on a modern PC with fast SSD and fast Internet connection). You can add <span>--prune-blockchain</span> argument to the command line to run a pruned node (3-4 times less disk usage)
|
||||
</ul></details>
|
||||
|
||||
@@ -256,6 +267,7 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<li>Once P2Pool sync is complete, XMRig should be able to connect to the stratum server on port <span>3333</span>
|
||||
<li>Run <span>./xmrig -o 127.0.0.1:3333</span>. Note that you don't need to specify wallet address for xmrig. Wallet address set in xmrig config will be ignored!
|
||||
<li>To set custom fixed difficulty for your miner (for example, <span>10000</span>), run <span>./xmrig -u x+10000 -o 127.0.0.1:3333</span>
|
||||
<li>To connect another mining rig to your P2Pool node, run <span>./xmrig -o YOUR_P2POOL_NODE_IP:3333</span> on that mining rig
|
||||
</ul></details>
|
||||
|
||||
<details><summary>Checking your progress</summary>
|
||||
|
||||
@@ -80,13 +80,22 @@ async function load_data() {
|
||||
let pool_stats_req = await fetch('api/pool/stats');
|
||||
let pool_blocks_req = await fetch('api/pool/blocks');
|
||||
let network_stats_req = await fetch('api/network/stats');
|
||||
let latest_release_req = await fetch('api/latest_release');
|
||||
|
||||
let pool_stats = JSON.parse(await pool_stats_req.text());
|
||||
let pool_blocks = JSON.parse(await pool_blocks_req.text());
|
||||
let network_stats = JSON.parse(await network_stats_req.text());
|
||||
let latest_release = JSON.parse(await latest_release_req.text());
|
||||
|
||||
let pool_hashrate = pool_stats.pool_statistics.hashRate / 1e6;
|
||||
let pplns_duration = pool_stats.pool_statistics.pplnsWeight / pool_stats.pool_statistics.hashRate;
|
||||
let min_payout = 0.6 * pool_stats.pool_statistics.sidechainDifficulty / pool_stats.pool_statistics.pplnsWeight;
|
||||
|
||||
document.getElementById("pool_hashrate").innerHTML = pool_hashrate.toFixed(3) + ' MH/s';
|
||||
document.getElementById("pplns_duration").innerHTML = elapsedTimeStr(0, pplns_duration, 0) + ' ' + Math.floor(pplns_duration % 60) + 's';
|
||||
document.getElementById("pool_miners").innerHTML = pool_stats.pool_statistics.miners;
|
||||
document.getElementById("min_payout").innerHTML = min_payout.toFixed(5) + ' XMR';
|
||||
document.getElementById("latest_release").innerHTML = '<a href="' + latest_release.html_url + '" target="_blank">' + latest_release.name + '</a>';
|
||||
|
||||
let ts = Math.floor(Date.now() / 1000);
|
||||
|
||||
@@ -185,6 +194,7 @@ function toggle_menu(name) {
|
||||
</head>
|
||||
<body onload="load_data();setInterval(load_data, 2000);toggle_menu(window.location.hash.substr(1));">
|
||||
<div style="font-size:3rem;text-align:center;">P2Pool mini</div><div style="font-size:1.1rem;text-align:center;">Decentralized Monero mining pool</div>
|
||||
<div style="font-size:1rem;text-align:center;">Latest release: <span id="latest_release"><a href="https://github.com/SChernykh/p2pool/releases/latest" target="_blank">P2Pool</a></span></div>
|
||||
<br>
|
||||
<table id="main_menu" style="width:100%;margin-left:auto;margin-right:auto;table-layout:fixed;text-align:center;-ms-touch-action:none;touch-action:none;"><tr>
|
||||
<td onclick="toggle_menu('pool')" id="button_pool">Pool</td>
|
||||
@@ -198,13 +208,14 @@ function toggle_menu(name) {
|
||||
<tr><td style="padding-bottom: 1rem;"></td><td></td><td></td></tr>
|
||||
<tr><td>Hashrate</td><td><span id="pool_hashrate">N/A</span></td><td><span id="monero_hashrate">N/A</span></td></tr>
|
||||
<tr><td>Miners</td><td><span id="pool_miners">N/A</span></td><td></td></tr>
|
||||
<tr><td>PPLNS window</td><td><span id="pplns_duration">N/A</span></td><td></td></tr>
|
||||
<tr><td>Last block</td><td><span id="pool_last_block">N/A</span></td><td><span id="monero_last_block">N/A</span></td></tr>
|
||||
<tr><td>Total blocks</td><td><span id="pool_total_blocks">N/A</span></td><td></td></tr>
|
||||
<tr><td>Current effort</td><td><span id="current_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td>Average effort<br><div style="text-align:center;font-size:0.9rem">last 50 blocks</div></td><td><span id="average_effort">N/A</span></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Fee</td><td>0%</td><td></td></tr>
|
||||
<tr><td>Min payout</td><td>0.0003 XMR</td><td></td></tr>
|
||||
<tr><td>Min payout</td><td><span id="min_payout">0.00027 XMR</span></td><td></td></tr>
|
||||
<tr><td>Payout scheme</td><td><a href="https://en.wikipedia.org/wiki/Mining_pool#Pay-per-last-N-shares" target="_blank">PPLNS</a></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td></tr>
|
||||
<tr><td>Statistics</td><td><a href="https://mini.p2pool.observer/" target="_blank">P2Pool observer</a></td><td></td></tr>
|
||||
@@ -237,8 +248,8 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<ul>
|
||||
<li>Download the latest Monero <a href="https://www.getmonero.org/downloads/" target="_blank">release</a>
|
||||
<li>[Optional] Open port <span>18080</span> (Monero p2p port) in your firewall to ensure better connectivity
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 64 --in-peers 32 --add-priority-node=node.supportxmr.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 16 --in-peers 8</span> instead.
|
||||
<li>Run <span>./monerod --zmq-pub tcp://127.0.0.1:18083 --out-peers 32 --in-peers 64 --add-priority-node=p2pmd.xmrvsbeast.com:18080 --add-priority-node=nodes.hashvault.pro:18080 --disable-dns-checkpoints --enable-dns-blocklist</span>
|
||||
<li>If your network connection's upload bandwidth is less than 10 Mbit, use <span>--out-peers 8 --in-peers 16</span> instead.
|
||||
<li>Wait until it's fully synchronized. If you didn't run Monero node before, it can take up to several days to synchronize (5-6 hours on a modern PC with fast SSD and fast Internet connection). You can add <span>--prune-blockchain</span> argument to the command line to run a pruned node (3-4 times less disk usage)
|
||||
</ul></details>
|
||||
|
||||
@@ -256,6 +267,7 @@ It's highly recommended to create a new wallet for mining because wallet address
|
||||
<li>Once P2Pool sync is complete, XMRig should be able to connect to the stratum server on port <span>3333</span>
|
||||
<li>Run <span>./xmrig -o 127.0.0.1:3333</span>. Note that you don't need to specify wallet address for xmrig. Wallet address set in xmrig config will be ignored!
|
||||
<li>To set custom fixed difficulty for your miner (for example, <span>10000</span>), run <span>./xmrig -u x+10000 -o 127.0.0.1:3333</span>
|
||||
<li>To connect another mining rig to your P2Pool node, run <span>./xmrig -o YOUR_P2POOL_NODE_IP:3333</span> on that mining rig
|
||||
</ul></details>
|
||||
|
||||
<details><summary>Checking your progress</summary>
|
||||
@@ -302,4 +314,4 @@ Donate to support the project:<br><a href="monero:44MnN1f3Eto8DZYUWuE5XZNUtE3vcR
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+1
-1
Submodule external/src/RandomX updated: 27a8cf0dfc...80d9f08b4f
Vendored
+1
-1
Submodule external/src/cppzmq updated: c66fc6094b...c94c20743e
Vendored
+1
-1
Submodule external/src/curl updated: 046209e561...50490c0679
Vendored
+1
-1
Submodule external/src/libuv updated: 55077af4b5...26d43f49ff
Vendored
+1
-1
Submodule external/src/libzmq updated: 8c725093ac...ec013f3a17
Vendored
+1
-1
Submodule external/src/miniupnp updated: e17579e4de...f7b437772b
Vendored
+1
-1
Submodule external/src/rapidjson updated: 914b772dfd...128cc9359f
+2
-2
@@ -20,7 +20,7 @@
|
||||
#include "pool_block.h"
|
||||
#include "p2p_server.h"
|
||||
|
||||
static constexpr char log_category_prefix[] = "BlockCache ";
|
||||
LOG_CATEGORY(BlockCache)
|
||||
|
||||
static constexpr uint32_t BLOCK_SIZE = 96 * 1024;
|
||||
static constexpr uint32_t NUM_BLOCKS = 4608;
|
||||
@@ -183,7 +183,7 @@ void BlockCache::store(const PoolBlock& block)
|
||||
memcpy(data + sizeof(uint32_t) + n1, sidechain_data.data(), n2);
|
||||
}
|
||||
|
||||
void BlockCache::load_all(SideChain& side_chain, P2PServer& server)
|
||||
void BlockCache::load_all(const SideChain& side_chain, P2PServer& server)
|
||||
{
|
||||
if (!m_impl->m_data) {
|
||||
return;
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public:
|
||||
~BlockCache();
|
||||
|
||||
void store(const PoolBlock& block);
|
||||
void load_all(SideChain& side_chain, P2PServer& server);
|
||||
void load_all(const SideChain& side_chain, P2PServer& server);
|
||||
void flush();
|
||||
|
||||
private:
|
||||
|
||||
+24
-18
@@ -32,10 +32,7 @@
|
||||
#include <ctime>
|
||||
#include <numeric>
|
||||
|
||||
static constexpr char log_category_prefix[] = "BlockTemplate ";
|
||||
|
||||
// Max P2P message size (128 KB) minus BLOCK_RESPONSE header (5 bytes)
|
||||
static constexpr size_t MAX_BLOCK_TEMPLATE_SIZE = 128 * 1024 - (1 + sizeof(uint32_t));
|
||||
LOG_CATEGORY(BlockTemplate)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
@@ -168,9 +165,7 @@ BlockTemplate& BlockTemplate::operator=(const BlockTemplate& b)
|
||||
static FORCEINLINE uint64_t get_base_reward(uint64_t already_generated_coins)
|
||||
{
|
||||
const uint64_t result = ~already_generated_coins >> 19;
|
||||
|
||||
constexpr uint64_t min_reward = 600000000000ULL;
|
||||
return (result < min_reward) ? min_reward : result;
|
||||
return (result < BASE_BLOCK_REWARD) ? BASE_BLOCK_REWARD : result;
|
||||
}
|
||||
|
||||
static FORCEINLINE uint64_t get_block_reward(uint64_t base_reward, uint64_t median_weight, uint64_t fees, uint64_t weight)
|
||||
@@ -353,14 +348,27 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||
b->m_transactions.resize(1);
|
||||
b->m_outputs.clear();
|
||||
|
||||
// Block template size without coinbase outputs and transactions (add 1+1 more bytes for output and tx count if they go above 128)
|
||||
size_t k = b->serialize_mainchain_data().size() + b->serialize_sidechain_data().size() + 2;
|
||||
// Block template size without coinbase outputs and transactions (minus 2 bytes for output and tx count dummy varints)
|
||||
size_t k = b->serialize_mainchain_data().size() + b->serialize_sidechain_data().size() - 2;
|
||||
|
||||
// a rough estimation of outputs' size
|
||||
// all outputs have <= 5 bytes for each output's reward, and up to 18 outputs can have 6 bytes for output's reward
|
||||
k += m_shares.size() * (5 /* reward */ + 1 /* tx_type */ + HASH_SIZE /* stealth address */ + 1 /* viewtag */) + 18;
|
||||
// Add output and tx count real varints
|
||||
writeVarint(m_shares.size(), [&k](uint8_t) { ++k; });
|
||||
writeVarint(m_mempoolTxs.size(), [&k](uint8_t) { ++k; });
|
||||
|
||||
const size_t max_transactions = (MAX_BLOCK_TEMPLATE_SIZE > k) ? ((MAX_BLOCK_TEMPLATE_SIZE - k) / HASH_SIZE) : 0;
|
||||
// Add a rough upper bound estimation of outputs' size. All outputs have <= 5 bytes for each output's reward (< 0.034359738368 XMR per output)
|
||||
k += m_shares.size() * (5 /* reward */ + 1 /* tx_type */ + HASH_SIZE /* stealth address */ + 1 /* viewtag */);
|
||||
|
||||
// >= 0.034359738368 XMR is required for a 6 byte varint, add 1 byte per each potential 6-byte varint
|
||||
{
|
||||
uint64_t r = BASE_BLOCK_REWARD;
|
||||
for (const auto& tx : m_mempoolTxs) {
|
||||
r += tx.fee;
|
||||
}
|
||||
k += r / 34359738368ULL;
|
||||
}
|
||||
|
||||
const size_t max_transactions = (MAX_BLOCK_SIZE > k) ? ((MAX_BLOCK_SIZE - k) / HASH_SIZE) : 0;
|
||||
LOGINFO(6, max_transactions << " transactions can be taken with current block size limit");
|
||||
|
||||
if (max_transactions == 0) {
|
||||
m_mempoolTxs.clear();
|
||||
@@ -638,7 +646,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||
|
||||
// Layout: [software id, version, random number, sidechain extra_nonce]
|
||||
uint32_t* sidechain_extra = m_poolBlockTemplate->m_sidechainExtraBuf;
|
||||
sidechain_extra[0] = 0;
|
||||
sidechain_extra[0] = static_cast<uint32_t>(SoftwareID::P2Pool);
|
||||
#ifdef P2POOL_SIDECHAIN_EXTRA_1
|
||||
sidechain_extra[1] = P2POOL_SIDECHAIN_EXTRA_1;
|
||||
#else
|
||||
@@ -678,6 +686,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||
|
||||
m_fullDataBlob = m_blockTemplateBlob;
|
||||
m_fullDataBlob.insert(m_fullDataBlob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
LOGINFO(6, "blob size = " << m_fullDataBlob.size());
|
||||
|
||||
m_poolBlockTemplate->m_sidechainId = calc_sidechain_hash(0);
|
||||
|
||||
@@ -705,9 +714,6 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||
if (result != 0) {
|
||||
LOGERR(1, "pool block blob generation and/or parsing is broken, error " << result);
|
||||
}
|
||||
else {
|
||||
LOGINFO(6, "blob size = " << m_fullDataBlob.size());
|
||||
}
|
||||
}
|
||||
|
||||
memset(m_minerTxKeccakState, 0, sizeof(m_minerTxKeccakState));
|
||||
@@ -1319,7 +1325,7 @@ bool BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
|
||||
}
|
||||
|
||||
m_poolBlockTemplate->m_verified = true;
|
||||
if (!m_sidechain->block_seen(*m_poolBlockTemplate)) {
|
||||
if (!m_sidechain->incoming_block_seen(*m_poolBlockTemplate)) {
|
||||
m_poolBlockTemplate->m_wantBroadcast = true;
|
||||
const bool result = m_sidechain->add_block(*m_poolBlockTemplate);
|
||||
if (!result) {
|
||||
|
||||
+25
-20
@@ -19,7 +19,7 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(disable : 4005 4061 4324 4365 4464 4619 4625 4626 4668 4710 4711 4804 4820 5039 5045 5220 5246 5264)
|
||||
#pragma warning(disable : 4005 4061 4324 4365 4464 4619 4625 4626 4668 4710 4711 4714 4804 4820 5039 5045 5220 5246 5264)
|
||||
#define FORCEINLINE __forceinline
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#define LIKELY(expression) expression
|
||||
@@ -56,7 +56,6 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include <signal.h>
|
||||
@@ -68,10 +67,18 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#elif defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) || defined(__MACH__)
|
||||
@@ -90,6 +97,7 @@
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
#define P2POOL_ASAN
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
extern "C" void __asan_poison_memory_region(void const volatile* addr, size_t size);
|
||||
@@ -153,8 +161,8 @@ struct alignas(uint64_t) hash
|
||||
|
||||
FORCEINLINE bool operator<(const hash& other) const
|
||||
{
|
||||
const uint64_t* a = reinterpret_cast<const uint64_t*>(h);
|
||||
const uint64_t* b = reinterpret_cast<const uint64_t*>(other.h);
|
||||
const uint64_t* a = u64();
|
||||
const uint64_t* b = other.u64();
|
||||
|
||||
if (a[3] < b[3]) return true;
|
||||
if (a[3] > b[3]) return false;
|
||||
@@ -170,18 +178,21 @@ struct alignas(uint64_t) hash
|
||||
|
||||
FORCEINLINE bool operator==(const hash& other) const
|
||||
{
|
||||
const uint64_t* a = reinterpret_cast<const uint64_t*>(h);
|
||||
const uint64_t* b = reinterpret_cast<const uint64_t*>(other.h);
|
||||
const uint64_t* a = u64();
|
||||
const uint64_t* b = other.u64();
|
||||
return (a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]) && (a[3] == b[3]);
|
||||
}
|
||||
|
||||
FORCEINLINE bool operator!=(const hash& other) const { return !operator==(other); }
|
||||
|
||||
FORCEINLINE bool empty() const {
|
||||
const uint64_t* a = reinterpret_cast<const uint64_t*>(h);
|
||||
const uint64_t* a = u64();
|
||||
return (a[0] == 0) && (a[1] == 0) && (a[2] == 0) && (a[3] == 0);
|
||||
}
|
||||
|
||||
FORCEINLINE uint64_t* u64() { return reinterpret_cast<uint64_t*>(h); }
|
||||
FORCEINLINE const uint64_t* u64() const { return reinterpret_cast<const uint64_t*>(h); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& s, const hash& d);
|
||||
friend std::istream& operator>>(std::istream& s, hash& d);
|
||||
};
|
||||
@@ -205,7 +216,7 @@ struct
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_addcarry_u64(_addcarry_u64(0, lo, b.lo, &lo), hi, b.hi, &hi);
|
||||
#elif __GNUC__
|
||||
#elif defined(__GNUC__) && !defined(DEV_CLANG_TIDY)
|
||||
*reinterpret_cast<unsigned __int128*>(this) += *reinterpret_cast<const unsigned __int128*>(&b);
|
||||
#else
|
||||
const uint64_t t = lo;
|
||||
@@ -222,7 +233,7 @@ struct
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_subborrow_u64(_subborrow_u64(0, lo, b.lo, &lo), hi, b.hi, &hi);
|
||||
#elif __GNUC__
|
||||
#elif defined(__GNUC__) && !defined(DEV_CLANG_TIDY)
|
||||
*reinterpret_cast<unsigned __int128*>(this) -= *reinterpret_cast<const unsigned __int128*>(&b);
|
||||
#else
|
||||
const uint64_t t = b.lo;
|
||||
@@ -437,19 +448,13 @@ struct raw_ip
|
||||
|
||||
FORCEINLINE bool operator!=(const raw_ip& other) const { return !operator==(other); }
|
||||
|
||||
FORCEINLINE bool is_localhost() const
|
||||
{
|
||||
static constexpr raw_ip localhost_ipv4 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 };
|
||||
static constexpr raw_ip localhost_ipv6 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
|
||||
FORCEINLINE bool is_localhost() const { return (*this == localhost_ipv4) || (*this == localhost_ipv6); }
|
||||
FORCEINLINE bool is_ipv4_prefix() const { return memcmp(data, ipv4_prefix, sizeof(ipv4_prefix)) == 0; }
|
||||
|
||||
return (*this == localhost_ipv4) || (*this == localhost_ipv6);
|
||||
}
|
||||
static const raw_ip localhost_ipv4;
|
||||
static const raw_ip localhost_ipv6;
|
||||
|
||||
FORCEINLINE bool is_ipv4_prefix() const
|
||||
{
|
||||
alignas(8) static constexpr uint8_t ipv4_prefix[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
|
||||
return memcmp(data, ipv4_prefix, sizeof(ipv4_prefix)) == 0;
|
||||
}
|
||||
alignas(8) static const uint8_t ipv4_prefix[12];
|
||||
};
|
||||
|
||||
static_assert(sizeof(raw_ip) == 16, "struct raw_ip has invalid size");
|
||||
|
||||
+144
-82
@@ -25,20 +25,21 @@
|
||||
#include "miner.h"
|
||||
#endif
|
||||
#include "side_chain.h"
|
||||
#include <iostream>
|
||||
#include "p2pool_api.h"
|
||||
#include "params.h"
|
||||
|
||||
static constexpr char log_category_prefix[] = "ConsoleCommands ";
|
||||
LOG_CATEGORY(ConsoleCommands)
|
||||
|
||||
static constexpr int DEFAULT_BACKLOG = 1;
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
ConsoleCommands::ConsoleCommands(p2pool* pool)
|
||||
: m_pool(pool)
|
||||
, m_loop{}
|
||||
, m_shutdownAsync{}
|
||||
: TCPServer(DEFAULT_BACKLOG, ConsoleClient::allocate)
|
||||
, m_pool(pool)
|
||||
, m_tty{}
|
||||
, m_stdin_pipe{}
|
||||
, m_stdin_handle(nullptr)
|
||||
, m_loopThread{}
|
||||
, m_readBuf{}
|
||||
, m_readBufInUse(false)
|
||||
{
|
||||
@@ -46,21 +47,9 @@ ConsoleCommands::ConsoleCommands(p2pool* pool)
|
||||
LOGINFO(3, "uv_guess_handle returned " << static_cast<int>(stdin_type));
|
||||
if (stdin_type != UV_TTY && stdin_type != UV_NAMED_PIPE) {
|
||||
LOGERR(1, "tty or named pipe is not available");
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
int err = uv_loop_init(&m_loop);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create event loop, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
err = uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
m_shutdownAsync.data = this;
|
||||
int err;
|
||||
|
||||
if (stdin_type == UV_TTY) {
|
||||
LOGINFO(3, "processing stdin as UV_TTY");
|
||||
@@ -71,7 +60,7 @@ ConsoleCommands::ConsoleCommands(p2pool* pool)
|
||||
}
|
||||
m_stdin_handle = reinterpret_cast<uv_stream_t*>(&m_tty);
|
||||
}
|
||||
else {
|
||||
else if (stdin_type == UV_NAMED_PIPE) {
|
||||
LOGINFO(3, "processing stdin as UV_NAMED_PIPE");
|
||||
err = uv_pipe_init(&m_loop, &m_stdin_pipe, 0);
|
||||
if (err) {
|
||||
@@ -85,26 +74,73 @@ ConsoleCommands::ConsoleCommands(p2pool* pool)
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
m_stdin_handle->data = this;
|
||||
|
||||
err = uv_read_start(m_stdin_handle, allocCallback, stdinReadCallback);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_read_start failed, error " << uv_err_name(err));
|
||||
if (m_stdin_handle) {
|
||||
m_stdin_handle->data = this;
|
||||
err = uv_read_start(m_stdin_handle, allocCallback, stdinReadCallback);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_read_start failed, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
std::random_device rd;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (start_listening(false, "127.0.0.1", 49152 + (rd() % 16384))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_listenPort < 0) {
|
||||
LOGERR(1, "failed to listen on TCP port");
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
if (m_pool->api() && m_pool->params().m_localStats) {
|
||||
m_pool->api()->set(p2pool_api::Category::LOCAL, "console",
|
||||
[stdin_type, this](log::Stream& s)
|
||||
{
|
||||
s << "{\"mode\":\"";
|
||||
|
||||
if (stdin_type == UV_TTY) {
|
||||
s << "tty";
|
||||
}
|
||||
else if (stdin_type == UV_NAMED_PIPE) {
|
||||
s << "pipe";
|
||||
}
|
||||
else {
|
||||
s << static_cast<int>(stdin_type);
|
||||
}
|
||||
|
||||
s << "\",\"tcp_port\":" << m_listenPort << '}';
|
||||
});
|
||||
}
|
||||
|
||||
err = uv_thread_create(&m_loopThread, loop, this);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
m_loopThreadCreated = true;
|
||||
}
|
||||
|
||||
ConsoleCommands::~ConsoleCommands()
|
||||
{
|
||||
uv_async_send(&m_shutdownAsync);
|
||||
uv_thread_join(&m_loopThread);
|
||||
LOGINFO(1, "stopped");
|
||||
shutdown_tcp();
|
||||
}
|
||||
|
||||
void ConsoleCommands::on_shutdown()
|
||||
{
|
||||
if (m_stdin_handle) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_stdin_handle), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ConsoleCommands::get_log_category() const
|
||||
{
|
||||
return log_category_prefix;
|
||||
}
|
||||
|
||||
typedef struct strconst {
|
||||
@@ -124,7 +160,7 @@ typedef struct cmd {
|
||||
cmdfunc *func;
|
||||
} cmd;
|
||||
|
||||
static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_showworkers, do_showbans, do_outpeers, do_inpeers, do_exit;
|
||||
static cmdfunc do_help, do_status, do_loglevel, do_addpeers, do_droppeers, do_showpeers, do_showworkers, do_showbans, do_showhosts, do_nexthost, do_outpeers, do_inpeers, do_exit, do_version;
|
||||
|
||||
#ifdef WITH_RANDOMX
|
||||
static cmdfunc do_start_mining, do_stop_mining;
|
||||
@@ -139,6 +175,8 @@ static cmd cmds[] = {
|
||||
{ STRCONST("peers"), "", "show all peers", do_showpeers },
|
||||
{ STRCONST("workers"), "", "show all connected workers", do_showworkers },
|
||||
{ STRCONST("bans"), "", "show all banned IPs", do_showbans },
|
||||
{ STRCONST("hosts"), "", "show Monero hosts", do_showhosts },
|
||||
{ STRCONST("next_host"), "", "switch to the next Monero host", do_nexthost },
|
||||
{ STRCONST("outpeers"), "<N>", "set maximum number of outgoing connections", do_outpeers },
|
||||
{ STRCONST("inpeers"), "<N>", "set maximum number of incoming connections", do_inpeers },
|
||||
#ifdef WITH_RANDOMX
|
||||
@@ -146,6 +184,7 @@ static cmd cmds[] = {
|
||||
{ STRCONST("stop_mining"), "", "stop mining", do_stop_mining },
|
||||
#endif
|
||||
{ STRCONST("exit"), "", "terminate p2pool", do_exit },
|
||||
{ STRCONST("version"), "", "show p2pool version", do_version },
|
||||
{ STRCNULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -163,13 +202,20 @@ static void do_status(p2pool *m_pool, const char * /* args */)
|
||||
if (m_pool->stratum_server()) {
|
||||
m_pool->stratum_server()->print_status();
|
||||
}
|
||||
if (m_pool->p2p_server()) {
|
||||
m_pool->p2p_server()->print_status();
|
||||
|
||||
P2PServer* p2p = m_pool->p2p_server();
|
||||
if (p2p) {
|
||||
p2p->print_status();
|
||||
}
|
||||
|
||||
#ifdef WITH_RANDOMX
|
||||
m_pool->print_miner_status();
|
||||
#endif
|
||||
bkg_jobs_tracker.print_status();
|
||||
|
||||
if (p2p) {
|
||||
p2p->check_for_updates(true);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_loglevel(p2pool * /* m_pool */, const char *args)
|
||||
@@ -180,6 +226,7 @@ static void do_loglevel(p2pool * /* m_pool */, const char *args)
|
||||
LOGINFO(0, "log level set to " << level);
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_addpeers(p2pool *m_pool, const char *args)
|
||||
{
|
||||
if (m_pool->p2p_server()) {
|
||||
@@ -187,6 +234,7 @@ static void do_addpeers(p2pool *m_pool, const char *args)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_droppeers(p2pool *m_pool, const char * /* args */)
|
||||
{
|
||||
if (m_pool->p2p_server()) {
|
||||
@@ -194,6 +242,7 @@ static void do_droppeers(p2pool *m_pool, const char * /* args */)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_showpeers(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
if (m_pool->p2p_server()) {
|
||||
@@ -201,6 +250,7 @@ static void do_showpeers(p2pool* m_pool, const char* /* args */)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_showworkers(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
if (m_pool->stratum_server()) {
|
||||
@@ -208,6 +258,7 @@ static void do_showworkers(p2pool* m_pool, const char* /* args */)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_showbans(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
if (m_pool->stratum_server()) {
|
||||
@@ -218,6 +269,19 @@ static void do_showbans(p2pool* m_pool, const char* /* args */)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_showhosts(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
m_pool->print_hosts();
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_nexthost(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
m_pool->reconnect_to_host();
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_outpeers(p2pool* m_pool, const char* args)
|
||||
{
|
||||
if (m_pool->p2p_server()) {
|
||||
@@ -226,6 +290,7 @@ static void do_outpeers(p2pool* m_pool, const char* args)
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_inpeers(p2pool* m_pool, const char* args)
|
||||
{
|
||||
if (m_pool->p2p_server()) {
|
||||
@@ -254,6 +319,17 @@ static void do_exit(p2pool *m_pool, const char * /* args */)
|
||||
m_pool->stop();
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterCallback
|
||||
static void do_version(p2pool* m_pool, const char* /* args */)
|
||||
{
|
||||
LOGINFO(0, log::LightCyan() << VERSION);
|
||||
|
||||
const P2PServer* p2p = m_pool->p2p_server();
|
||||
if (p2p) {
|
||||
p2p->check_for_updates(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleCommands::allocCallback(uv_handle_t* handle, size_t /*suggested_size*/, uv_buf_t* buf)
|
||||
{
|
||||
ConsoleCommands* pThis = static_cast<ConsoleCommands*>(handle->data);
|
||||
@@ -274,46 +350,7 @@ void ConsoleCommands::stdinReadCallback(uv_stream_t* stream, ssize_t nread, cons
|
||||
ConsoleCommands* pThis = static_cast<ConsoleCommands*>(stream->data);
|
||||
|
||||
if (nread > 0) {
|
||||
std::string& command = pThis->m_command;
|
||||
command.append(buf->base, nread);
|
||||
|
||||
do {
|
||||
size_t k = command.find_first_of("\r\n");
|
||||
if (k == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
command[k] = '\0';
|
||||
|
||||
cmd* c = cmds;
|
||||
for (; c->name.len; ++c) {
|
||||
if (!strncmp(command.c_str(), c->name.str, c->name.len)) {
|
||||
const char* args = (c->name.len + 1 <= k) ? (command.c_str() + c->name.len + 1) : "";
|
||||
|
||||
// Skip spaces
|
||||
while ((args[0] == ' ') || (args[0] == '\t')) {
|
||||
++args;
|
||||
}
|
||||
|
||||
// Check if an argument is required
|
||||
if (strlen(c->arg) && !strlen(args)) {
|
||||
LOGWARN(0, c->name.str << " requires arguments");
|
||||
do_help(nullptr, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
c->func(pThis->m_pool, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->name.len) {
|
||||
LOGWARN(0, "Unknown command " << command.c_str());
|
||||
do_help(nullptr, nullptr);
|
||||
}
|
||||
|
||||
k = command.find_first_not_of("\r\n", k + 1);
|
||||
command.erase(0, k);
|
||||
} while (true);
|
||||
pThis->process_input(pThis->m_command, buf->base, static_cast<uint32_t>(nread));
|
||||
}
|
||||
else if (nread < 0) {
|
||||
LOGWARN(4, "read error " << uv_err_name(static_cast<int>(nread)));
|
||||
@@ -322,23 +359,48 @@ void ConsoleCommands::stdinReadCallback(uv_stream_t* stream, ssize_t nread, cons
|
||||
pThis->m_readBufInUse = false;
|
||||
}
|
||||
|
||||
void ConsoleCommands::loop(void* data)
|
||||
|
||||
void ConsoleCommands::process_input(std::string& command, char* data, uint32_t size)
|
||||
{
|
||||
LOGINFO(1, "event loop started");
|
||||
command.append(data, size);
|
||||
|
||||
ConsoleCommands* pThis = static_cast<ConsoleCommands*>(data);
|
||||
do {
|
||||
size_t k = command.find_first_of("\r\n");
|
||||
if (k == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
command[k] = '\0';
|
||||
|
||||
int err = uv_run(&pThis->m_loop, UV_RUN_DEFAULT);
|
||||
if (err) {
|
||||
LOGWARN(1, "uv_run returned " << err);
|
||||
}
|
||||
cmd* c = cmds;
|
||||
for (; c->name.len; ++c) {
|
||||
if (!strncmp(command.c_str(), c->name.str, c->name.len)) {
|
||||
const char* args = (c->name.len + 1 <= k) ? (command.c_str() + c->name.len + 1) : "";
|
||||
|
||||
err = uv_loop_close(&pThis->m_loop);
|
||||
if (err) {
|
||||
LOGWARN(1, "uv_loop_close returned error " << uv_err_name(err));
|
||||
}
|
||||
// Skip spaces
|
||||
while ((args[0] == ' ') || (args[0] == '\t')) {
|
||||
++args;
|
||||
}
|
||||
|
||||
LOGINFO(1, "event loop stopped");
|
||||
// Check if an argument is required
|
||||
if (strlen(c->arg) && !strlen(args)) {
|
||||
LOGWARN(0, c->name.str << " requires arguments");
|
||||
do_help(nullptr, nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
c->func(m_pool, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->name.len) {
|
||||
LOGWARN(0, "Unknown command " << command.c_str());
|
||||
do_help(nullptr, nullptr);
|
||||
}
|
||||
|
||||
k = command.find_first_not_of("\r\n", k + 1);
|
||||
command.erase(0, k);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+26
-14
@@ -18,43 +18,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "uv_util.h"
|
||||
#include "tcp_server.h"
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
class p2pool;
|
||||
|
||||
class ConsoleCommands : public nocopy_nomove
|
||||
class ConsoleCommands : public TCPServer
|
||||
{
|
||||
public:
|
||||
explicit ConsoleCommands(p2pool* pool);
|
||||
~ConsoleCommands();
|
||||
|
||||
struct ConsoleClient : public Client
|
||||
{
|
||||
ConsoleClient() : Client(m_consoleReadBuf, sizeof(m_consoleReadBuf)) {}
|
||||
~ConsoleClient() {}
|
||||
|
||||
static Client* allocate() { return new ConsoleClient(); }
|
||||
|
||||
size_t size() const override { return sizeof(ConsoleClient); }
|
||||
|
||||
bool on_connect() override { return true; };
|
||||
bool on_read(char* data, uint32_t size) override { static_cast<ConsoleCommands*>(m_owner)->process_input(m_command, data, size); return true; };
|
||||
|
||||
char m_consoleReadBuf[1024] = {};
|
||||
|
||||
std::string m_command;
|
||||
};
|
||||
|
||||
void on_shutdown() override;
|
||||
|
||||
private:
|
||||
const char* get_log_category() const override;
|
||||
|
||||
p2pool* m_pool;
|
||||
|
||||
uv_loop_t m_loop;
|
||||
uv_async_t m_shutdownAsync;
|
||||
uv_tty_t m_tty;
|
||||
uv_pipe_t m_stdin_pipe;
|
||||
uv_stream_t* m_stdin_handle;
|
||||
uv_thread_t m_loopThread;
|
||||
|
||||
char m_readBuf[64];
|
||||
char m_readBuf[1024];
|
||||
bool m_readBufInUse;
|
||||
|
||||
std::string m_command;
|
||||
|
||||
static void loop(void* data);
|
||||
|
||||
static void on_shutdown(uv_async_t* async)
|
||||
{
|
||||
ConsoleCommands* pThis = reinterpret_cast<ConsoleCommands*>(async->data);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pThis->m_shutdownAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(pThis->m_stdin_handle), nullptr);
|
||||
}
|
||||
|
||||
static void allocCallback(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
|
||||
static void stdinReadCallback(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
|
||||
|
||||
void process_input(std::string& command, char* data, uint32_t size);
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+3
-1
@@ -80,7 +80,7 @@ static FORCEINLINE bool less32(const uint8_t* k0, const uint8_t* k1)
|
||||
return false;
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameter
|
||||
// cppcheck-suppress constParameterReference
|
||||
void generate_keys(hash& pub, hash& sec)
|
||||
{
|
||||
do {
|
||||
@@ -93,6 +93,7 @@ void generate_keys(hash& pub, hash& sec)
|
||||
ge_p3_tobytes(pub.h, &point);
|
||||
}
|
||||
|
||||
// cppcheck-suppress constParameterReference
|
||||
void generate_keys_deterministic(hash& pub, hash& sec, const uint8_t* entropy, size_t len)
|
||||
{
|
||||
uint32_t counter = 0;
|
||||
@@ -356,6 +357,7 @@ private:
|
||||
hash m_derivation;
|
||||
uint32_t m_viewTags1[2] = { 0xFFFFFFFFUL, 0xFFFFFFFFUL };
|
||||
std::vector<uint32_t> m_viewTags2;
|
||||
// cppcheck-suppress unusedStructMember
|
||||
uint64_t m_timestamp;
|
||||
|
||||
FORCEINLINE bool find_view_tag(size_t output_index, uint8_t& view_tag) const
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "json_rpc_request.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
static constexpr char log_category_prefix[] = "JSONRPCRequest ";
|
||||
LOG_CATEGORY(JSONRPCRequest)
|
||||
|
||||
namespace p2pool {
|
||||
namespace JSONRPCRequest {
|
||||
@@ -78,6 +78,9 @@ struct CurlContext
|
||||
std::string m_error;
|
||||
|
||||
curl_slist* m_headers;
|
||||
|
||||
uint64_t m_startTime;
|
||||
uint64_t m_connectedTime;
|
||||
};
|
||||
|
||||
CurlContext::CurlContext(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop)
|
||||
@@ -90,6 +93,8 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
|
||||
, m_handle(nullptr)
|
||||
, m_req(req)
|
||||
, m_headers(nullptr)
|
||||
, m_startTime(0)
|
||||
, m_connectedTime(0)
|
||||
{
|
||||
m_pollHandles.reserve(2);
|
||||
|
||||
@@ -171,10 +176,16 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
curl_easy_setopt_checked(m_handle, CURLOPT_BUFFERSIZE, 102400L);
|
||||
|
||||
curl_easy_setopt_checked(m_handle, CURLOPT_WRITEFUNCTION, write_func);
|
||||
curl_easy_setopt_checked(m_handle, CURLOPT_WRITEDATA, this);
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
const int timeout = 10;
|
||||
#else
|
||||
const int timeout = proxy.empty() ? 1 : 5;
|
||||
#endif
|
||||
|
||||
curl_easy_setopt_checked(m_handle, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt_checked(m_handle, CURLOPT_POSTFIELDS, m_req.c_str());
|
||||
@@ -210,12 +221,19 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_timer), nullptr);
|
||||
throw std::runtime_error("curl_multi_add_handle failed");
|
||||
}
|
||||
|
||||
m_startTime = microseconds_since_epoch();
|
||||
}
|
||||
|
||||
CurlContext::~CurlContext()
|
||||
{
|
||||
double tcp_ping = 0.0;
|
||||
|
||||
if (m_error.empty() && !m_response.empty()) {
|
||||
(*m_callback)(m_response.data(), m_response.size());
|
||||
if (m_connectedTime) {
|
||||
tcp_ping = static_cast<double>(m_connectedTime - m_startTime) / 1000.0;
|
||||
}
|
||||
(*m_callback)(m_response.data(), m_response.size(), tcp_ping);
|
||||
}
|
||||
delete m_callback;
|
||||
|
||||
@@ -228,7 +246,7 @@ CurlContext::~CurlContext()
|
||||
}
|
||||
}
|
||||
|
||||
(*m_closeCallback)(m_error.c_str(), m_error.length());
|
||||
(*m_closeCallback)(m_error.c_str(), m_error.length(), tcp_ping);
|
||||
delete m_closeCallback;
|
||||
|
||||
curl_slist_free_all(m_headers);
|
||||
@@ -357,6 +375,10 @@ void CurlContext::on_timeout(uv_handle_t* req)
|
||||
|
||||
size_t CurlContext::on_write(const void* buffer, size_t size, size_t count)
|
||||
{
|
||||
if (!m_connectedTime) {
|
||||
m_connectedTime = microseconds_since_epoch();
|
||||
}
|
||||
|
||||
const size_t realsize = size * count;
|
||||
const char* p = reinterpret_cast<const char*>(buffer);
|
||||
m_response.insert(m_response.end(), p, p + realsize);
|
||||
@@ -365,6 +387,8 @@ size_t CurlContext::on_write(const void* buffer, size_t size, size_t count)
|
||||
|
||||
void CurlContext::curl_perform(uv_poll_t* req, int status, int events)
|
||||
{
|
||||
CurlContext* ctx = reinterpret_cast<CurlContext*>(req->data);
|
||||
|
||||
int flags = 0;
|
||||
if (status < 0) {
|
||||
flags |= CURL_CSELECT_ERR;
|
||||
@@ -372,11 +396,14 @@ void CurlContext::curl_perform(uv_poll_t* req, int status, int events)
|
||||
}
|
||||
else {
|
||||
if (events & UV_READABLE) flags |= CURL_CSELECT_IN;
|
||||
if (events & UV_WRITABLE) flags |= CURL_CSELECT_OUT;
|
||||
if (events & UV_WRITABLE) {
|
||||
flags |= CURL_CSELECT_OUT;
|
||||
if (!ctx->m_connectedTime) {
|
||||
ctx->m_connectedTime = microseconds_since_epoch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurlContext* ctx = reinterpret_cast<CurlContext*>(req->data);
|
||||
|
||||
int running_handles = 0;
|
||||
auto it = std::find_if(ctx->m_pollHandles.begin(), ctx->m_pollHandles.end(), [req](const auto& value) { return value.second == req; });
|
||||
if (it != ctx->m_pollHandles.end()) {
|
||||
@@ -467,7 +494,7 @@ void Call(const std::string& address, int port, const std::string& req, const st
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
const char* msg = e.what();
|
||||
(*close_cb)(msg, strlen(msg));
|
||||
(*close_cb)(msg, strlen(msg), 0.0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+5
-17
@@ -20,29 +20,17 @@
|
||||
namespace p2pool {
|
||||
namespace JSONRPCRequest {
|
||||
|
||||
struct CallbackBase
|
||||
{
|
||||
virtual ~CallbackBase() {}
|
||||
virtual void operator()(const char* data, size_t size) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Callback : public CallbackBase
|
||||
{
|
||||
explicit FORCEINLINE Callback(T&& cb) : m_cb(std::move(cb)) {}
|
||||
void operator()(const char* data, size_t size) override { m_cb(data, size); }
|
||||
|
||||
private:
|
||||
Callback& operator=(Callback&&) = delete;
|
||||
T m_cb;
|
||||
};
|
||||
typedef Callback<void, const char*, size_t, double>::Base CallbackBase;
|
||||
|
||||
void Call(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop);
|
||||
|
||||
template<typename T, typename U>
|
||||
FORCEINLINE void call(const std::string& address, int port, const std::string& req, const std::string& auth, const std::string& proxy, T&& cb, U&& close_cb, uv_loop_t* loop = nullptr)
|
||||
{
|
||||
Call(address, port, req, auth, proxy, new Callback<T>(std::move(cb)), new Callback<U>(std::move(close_cb)), loop);
|
||||
typedef Callback<void, const char*, size_t, double>::Derived<T> CallbackT;
|
||||
typedef Callback<void, const char*, size_t, double>::Derived<U> CallbackU;
|
||||
|
||||
Call(address, port, req, auth, proxy, new CallbackT(std::move(cb)), new CallbackU(std::move(close_cb)), loop);
|
||||
}
|
||||
|
||||
} // namespace JSONRPCRequest
|
||||
|
||||
+114
-55
@@ -22,12 +22,14 @@
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
#include <clocale>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
static constexpr char log_category_prefix[] = "Log ";
|
||||
LOG_CATEGORY(Log)
|
||||
|
||||
static constexpr char log_file_name[] = "p2pool.log";
|
||||
|
||||
namespace p2pool {
|
||||
@@ -42,8 +44,66 @@ bool CONSOLE_COLORS = true;
|
||||
#ifdef _WIN32
|
||||
static const HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
static const HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
static const HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(NDEBUG)
|
||||
|
||||
#include <DbgHelp.h>
|
||||
|
||||
#pragma comment(lib, "Dbghelp.lib")
|
||||
|
||||
LONG WINAPI UnhandledExceptionFilter(_In_ _EXCEPTION_POINTERS* exception_pointers)
|
||||
{
|
||||
constexpr size_t MAX_FRAMES = 32;
|
||||
|
||||
void* stack_trace[MAX_FRAMES] = {};
|
||||
DWORD hash;
|
||||
CaptureStackBackTrace(1, MAX_FRAMES, stack_trace, &hash);
|
||||
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {};
|
||||
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
IMAGEHLP_LINE64 line{};
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
const HANDLE h = GetCurrentProcess();
|
||||
|
||||
const uint32_t code = (exception_pointers && exception_pointers->ExceptionRecord) ? exception_pointers->ExceptionRecord->ExceptionCode : 0;
|
||||
|
||||
fprintf(stderr, "\n\nUnhandled exception %X at:\n", code);
|
||||
fflush(stderr);
|
||||
|
||||
for (size_t j = 0; j < MAX_FRAMES; ++j) {
|
||||
const DWORD64 address = reinterpret_cast<DWORD64>(stack_trace[j]);
|
||||
DWORD t = 0;
|
||||
if (SymFromAddr(h, address, nullptr, pSymbol) && SymGetLineFromAddr64(h, address, &t, &line)) {
|
||||
fprintf(stderr, "%s (%s, line %lu)\n", line.FileName, pSymbol->Name, line.LineNumber);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n\n");
|
||||
fflush(stderr);
|
||||
|
||||
// Normal logging might be broken at this point, but try to log it anyway
|
||||
LOGERR(0, "Unhandled exception " << log::Hex(code) << " at:");
|
||||
|
||||
for (size_t j = 0; j < MAX_FRAMES; ++j) {
|
||||
const DWORD64 address = reinterpret_cast<DWORD64>(stack_trace[j]);
|
||||
DWORD t = 0;
|
||||
if (SymFromAddr(h, address, nullptr, pSymbol) && SymGetLineFromAddr64(h, address, &t, &line)) {
|
||||
LOGERR(0, line.FileName << " (" << static_cast<const char*>(pSymbol->Name) << ", line " << static_cast<size_t>(line.LineNumber) << ')');
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif // _MSC_VER && !NDEBUG
|
||||
#endif // _WIN32
|
||||
|
||||
class Worker
|
||||
{
|
||||
@@ -60,8 +120,15 @@ public:
|
||||
, m_started{ false }
|
||||
, m_stopped(false)
|
||||
{
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG)
|
||||
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
|
||||
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||
#endif
|
||||
|
||||
set_main_thread();
|
||||
|
||||
std::setlocale(LC_ALL, "en_001");
|
||||
|
||||
m_logFile.open(log_file_name, std::ios::app | std::ios::binary);
|
||||
|
||||
m_buf.resize(BUF_SIZE);
|
||||
@@ -136,6 +203,10 @@ public:
|
||||
#endif
|
||||
|
||||
m_logFile.close();
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG)
|
||||
SymCleanup(GetCurrentProcess());
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE void write(const char* buf, uint32_t size)
|
||||
@@ -154,7 +225,9 @@ public:
|
||||
memcpy(p + 1, buf + 1, size - 1);
|
||||
|
||||
// Ensure memory order in the writer thread
|
||||
#ifndef DEV_WITH_TSAN
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#endif
|
||||
|
||||
// Mark that everything is written into this log slot
|
||||
p[0] = buf[0] + 1;
|
||||
@@ -172,7 +245,7 @@ private:
|
||||
|
||||
const uint32_t N = std::min(std::max(std::thread::hardware_concurrency(), 4U), 8U);
|
||||
|
||||
char buf[40] = {};
|
||||
static char buf[40] = {};
|
||||
log::Stream s(buf);
|
||||
s << "UV_THREADPOOL_SIZE=" << N << '\0';
|
||||
|
||||
@@ -221,7 +294,9 @@ private:
|
||||
}
|
||||
|
||||
// Ensure memory order in the reader thread
|
||||
#ifndef DEV_WITH_TSAN
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#endif
|
||||
|
||||
uint32_t size = static_cast<uint8_t>(p[2]);
|
||||
size = (size << 8) + static_cast<uint8_t>(p[1]);
|
||||
@@ -237,12 +312,7 @@ private:
|
||||
strip_colors(p, size);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD k;
|
||||
WriteConsole((severity == 1) ? hStdOut : hStdErr, p, size, &k, nullptr);
|
||||
#else
|
||||
fwrite(p, 1, size, (severity == 1) ? stdout : stderr);
|
||||
#endif
|
||||
|
||||
if (m_logFile.is_open()) {
|
||||
if (c) {
|
||||
@@ -281,14 +351,17 @@ private:
|
||||
m_logFile.open(log_file_name, std::ios::app | std::ios::binary);
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static FORCEINLINE void strip_colors(char* buf, uint32_t& size)
|
||||
{
|
||||
char* p_read = buf;
|
||||
const char* p_read = buf;
|
||||
char* p_write = buf;
|
||||
char* buf_end = buf + size;
|
||||
const char* buf_end = buf + size;
|
||||
|
||||
bool is_color = false;
|
||||
|
||||
@@ -329,6 +402,31 @@ static Worker worker;
|
||||
|
||||
#endif // P2POOL_LOG_DISABLE
|
||||
|
||||
static FORCEINLINE void writeCurrentTime(Stream& s)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
const system_clock::time_point now = system_clock::now();
|
||||
const time_t t0 = system_clock::to_time_t(now);
|
||||
|
||||
tm t;
|
||||
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&t, &t0);
|
||||
#else
|
||||
gmtime_r(&t0, &t);
|
||||
#endif
|
||||
|
||||
s.setNumberWidth(2);
|
||||
s << (t.tm_year + 1900) << '-' << (t.tm_mon + 1) << '-' << t.tm_mday << ' ' << t.tm_hour << ':' << t.tm_min << ':' << t.tm_sec << '.';
|
||||
|
||||
const int32_t mcs = time_point_cast<microseconds>(now).time_since_epoch().count() % 1000000;
|
||||
|
||||
s.setNumberWidth(4);
|
||||
s << (mcs / 100);
|
||||
s.setNumberWidth(1);
|
||||
}
|
||||
|
||||
NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
|
||||
{
|
||||
m_stackBuf[BUF_SIZE] = '\0';
|
||||
@@ -336,7 +434,7 @@ NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
|
||||
m_pos = 3;
|
||||
|
||||
*this << Cyan();
|
||||
writeCurrentTime();
|
||||
writeCurrentTime(*this);
|
||||
*this << NoColor() << ' ';
|
||||
}
|
||||
|
||||
@@ -364,53 +462,14 @@ void stop()
|
||||
#endif
|
||||
}
|
||||
|
||||
NOINLINE void Stream::writeCurrentTime()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
const system_clock::time_point now = system_clock::now();
|
||||
const time_t t0 = system_clock::to_time_t(now);
|
||||
|
||||
tm t;
|
||||
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&t, &t0);
|
||||
#else
|
||||
gmtime_r(&t0, &t);
|
||||
#endif
|
||||
|
||||
m_numberWidth = 2;
|
||||
*this << (t.tm_year + 1900) << '-' << (t.tm_mon + 1) << '-' << t.tm_mday << ' ' << t.tm_hour << ':' << t.tm_min << ':' << t.tm_sec << '.';
|
||||
|
||||
const int32_t mcs = time_point_cast<microseconds>(now).time_since_epoch().count() % 1000000;
|
||||
|
||||
m_numberWidth = 4;
|
||||
*this << (mcs / 100);
|
||||
// cppcheck-suppress redundantAssignment
|
||||
m_numberWidth = 1;
|
||||
}
|
||||
|
||||
NOINLINE void Stream::Entry<raw_ip>::put(const raw_ip& value, Stream* wrapper)
|
||||
{
|
||||
const char* addr_str;
|
||||
const bool is_ipv4 = value.is_ipv4_prefix();
|
||||
|
||||
char addr_str_buf[64];
|
||||
const char* addr_str = inet_ntop(is_ipv4 ? AF_INET : AF_INET6, value.data + (is_ipv4 ? 12 : 0), addr_str_buf, sizeof(addr_str_buf));
|
||||
|
||||
static constexpr uint8_t ipv4_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255 };
|
||||
const bool is_v6 = (memcmp(value.data, ipv4_prefix, 12) != 0);
|
||||
|
||||
if (is_v6) {
|
||||
addr_str = inet_ntop(AF_INET6, value.data, addr_str_buf, sizeof(addr_str_buf));
|
||||
}
|
||||
else {
|
||||
addr_str = inet_ntop(AF_INET, value.data + 12, addr_str_buf, sizeof(addr_str_buf));
|
||||
}
|
||||
|
||||
if (addr_str) {
|
||||
*wrapper << addr_str;
|
||||
}
|
||||
else {
|
||||
*wrapper << "N/A";
|
||||
}
|
||||
*wrapper << (addr_str ? addr_str : "N/A");
|
||||
}
|
||||
|
||||
NOINLINE void Stream::Entry<Wallet>::put(const Wallet& w, Stream* wrapper)
|
||||
|
||||
@@ -38,9 +38,18 @@ struct Stream
|
||||
enum params : int { BUF_SIZE = 1024 - 1 };
|
||||
|
||||
template<size_t N>
|
||||
explicit FORCEINLINE Stream(char (&buf)[N]) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(N - 1) {}
|
||||
explicit FORCEINLINE Stream(char (&buf)[N]) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(N - 1), m_spilled(0) {}
|
||||
|
||||
FORCEINLINE Stream(void* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(reinterpret_cast<char*>(buf)), m_bufSize(static_cast<int>(size) - 1) {}
|
||||
FORCEINLINE Stream(void* buf, size_t size) { reset(buf, size); }
|
||||
|
||||
FORCEINLINE void reset(void* buf, size_t size)
|
||||
{
|
||||
m_pos = 0;
|
||||
m_numberWidth = 1;
|
||||
m_buf = reinterpret_cast<char*>(buf);
|
||||
m_bufSize = static_cast<int>(size) - 1;
|
||||
m_spilled = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Entry
|
||||
@@ -65,24 +74,23 @@ struct Stream
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, int base = 10>
|
||||
template<typename T, unsigned int base = 10>
|
||||
NOINLINE void writeInt(T data)
|
||||
{
|
||||
static_assert(1 < base && base <= 64, "Invalid base");
|
||||
|
||||
const T data_with_sign = data;
|
||||
data = abs(data);
|
||||
const bool negative = (data != data_with_sign);
|
||||
const bool negative = is_negative(data);
|
||||
std::make_unsigned_t<T> udata = abs(data);
|
||||
|
||||
char buf[32];
|
||||
size_t k = sizeof(buf);
|
||||
int w = m_numberWidth;
|
||||
|
||||
do {
|
||||
buf[--k] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"[data % base];
|
||||
data /= base;
|
||||
buf[--k] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"[udata % base];
|
||||
udata /= base;
|
||||
--w;
|
||||
} while ((data > 0) || (w > 0));
|
||||
} while (udata || (w > 0));
|
||||
|
||||
if (negative) {
|
||||
buf[--k] = '-';
|
||||
@@ -96,6 +104,7 @@ struct Stream
|
||||
const int n = static_cast<int>(n0);
|
||||
const int pos = m_pos;
|
||||
if (pos + n > m_bufSize) {
|
||||
m_spilled += n;
|
||||
return;
|
||||
}
|
||||
memcpy(m_buf + pos, buf, n);
|
||||
@@ -105,12 +114,11 @@ struct Stream
|
||||
FORCEINLINE int getNumberWidth() const { return m_numberWidth; }
|
||||
FORCEINLINE void setNumberWidth(int width) { m_numberWidth = width; }
|
||||
|
||||
NOINLINE void writeCurrentTime();
|
||||
|
||||
int m_pos;
|
||||
int m_numberWidth;
|
||||
char* m_buf;
|
||||
int m_bufSize;
|
||||
int m_spilled;
|
||||
};
|
||||
|
||||
struct Writer : public Stream
|
||||
@@ -146,7 +154,13 @@ COLOR_ENTRY(LightCyan, "\x1b[0;96m")
|
||||
|
||||
template<size_t N> struct Stream::Entry<char[N]>
|
||||
{
|
||||
static FORCEINLINE void put(const char (&data)[N], Stream* wrapper) { wrapper->writeBuf(data, N - 1); }
|
||||
template<typename T>
|
||||
// cppcheck-suppress constParameterReference
|
||||
static FORCEINLINE void put(T (&data)[N], Stream* wrapper)
|
||||
{
|
||||
static_assert(std::is_same<T, const char>::value, "Non-const char buffer must be cast to \"const char*\"");
|
||||
wrapper->writeBuf(data, N - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct Stream::Entry<const char*>
|
||||
@@ -156,6 +170,7 @@ template<> struct Stream::Entry<const char*>
|
||||
|
||||
template<> struct Stream::Entry<char*>
|
||||
{
|
||||
// cppcheck-suppress constParameterPointer
|
||||
static FORCEINLINE void put(char* data, Stream* wrapper) { wrapper->writeBuf(data, strlen(data)); }
|
||||
};
|
||||
|
||||
@@ -281,7 +296,10 @@ template<> struct log::Stream::Entry<const_buf>
|
||||
|
||||
struct hex_buf
|
||||
{
|
||||
FORCEINLINE hex_buf(const uint8_t* data, size_t size) : m_data(data), m_size(size) {}
|
||||
FORCEINLINE hex_buf(const void* data, size_t size) : m_data(reinterpret_cast<const uint8_t*>(data)), m_size(size) {}
|
||||
|
||||
template<typename T>
|
||||
explicit FORCEINLINE hex_buf(const T* data) : m_data(reinterpret_cast<const uint8_t*>(data)), m_size(sizeof(T)) {}
|
||||
|
||||
const uint8_t* m_data;
|
||||
size_t m_size;
|
||||
@@ -486,28 +504,33 @@ struct DummyStream
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __COVERITY__
|
||||
// Coverity doesn't like this macro - CID 393138: Big parameter passed by value (PASS_BY_VALUE)
|
||||
#define SIDE_EFFECT_CHECK(level, ...)
|
||||
#else
|
||||
#define SIDE_EFFECT_CHECK(level, ...) \
|
||||
do { \
|
||||
if (0) { \
|
||||
MSVC_PRAGMA(warning(suppress:26444)) \
|
||||
[=]() { \
|
||||
log::DummyStream x; \
|
||||
x << (level) << __VA_ARGS__; \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
if (0) { \
|
||||
MSVC_PRAGMA(warning(suppress:26444)) \
|
||||
[=]() { \
|
||||
log::DummyStream x; \
|
||||
x << (level) << __VA_ARGS__; \
|
||||
}; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define LOG_CATEGORY(category) static constexpr char log_category_prefix[] = #category " ";
|
||||
|
||||
#ifdef P2POOL_LOG_DISABLE
|
||||
|
||||
#define LOGINFO(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
#define LOGWARN(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
#define LOGERR(level, ...) SIDE_EFFECT_CHECK(level, __VA_ARGS__)
|
||||
#define LOGINFO(level, ...) SIDE_EFFECT_CHECK(level, log_category_prefix << __VA_ARGS__)
|
||||
#define LOGWARN(level, ...) SIDE_EFFECT_CHECK(level, log_category_prefix << __VA_ARGS__)
|
||||
#define LOGERR(level, ...) SIDE_EFFECT_CHECK(level, log_category_prefix << __VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(level, severity, ...) \
|
||||
do { \
|
||||
SIDE_EFFECT_CHECK(level, __VA_ARGS__); \
|
||||
SIDE_EFFECT_CHECK(level, log_category_prefix << __VA_ARGS__); \
|
||||
if ((level) <= log::GLOBAL_LOG_LEVEL) { \
|
||||
log::Writer CONCAT(log_wrapper_, __LINE__)(severity); \
|
||||
CONCAT(log_wrapper_, __LINE__) << log::Gray() << log_category_prefix; \
|
||||
|
||||
+96
-3
@@ -22,6 +22,10 @@
|
||||
#include "p2p_server.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef WITH_RANDOMX
|
||||
#include "randomx.h"
|
||||
#endif
|
||||
|
||||
void p2pool_usage()
|
||||
{
|
||||
printf("P2Pool %s\n"
|
||||
@@ -58,6 +62,7 @@ void p2pool_usage()
|
||||
"--no-igd An alias for --no-upnp\n"
|
||||
"--upnp-stratum Port forward Stratum port (it's not forwarded by default)\n"
|
||||
#endif
|
||||
"--version Print p2pool's version and build details\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",
|
||||
@@ -75,8 +80,85 @@ void p2pool_usage()
|
||||
);
|
||||
}
|
||||
|
||||
void memory_tracking_start();
|
||||
void memory_tracking_stop();
|
||||
void p2pool_version()
|
||||
{
|
||||
printf("P2Pool %s\n", p2pool::VERSION);
|
||||
}
|
||||
|
||||
int p2pool_test()
|
||||
{
|
||||
#ifdef WITH_RANDOMX
|
||||
const char myKey[] = "test key 000";
|
||||
const char myInput[] = "This is a test";
|
||||
char hash[RANDOMX_HASH_SIZE];
|
||||
|
||||
const randomx_flags flags = randomx_get_flags() | RANDOMX_FLAG_FULL_MEM;
|
||||
randomx_cache* myCache = randomx_alloc_cache(flags);
|
||||
if (!myCache) {
|
||||
printf("Cache allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
randomx_init_cache(myCache, myKey, sizeof(myKey) - 1);
|
||||
|
||||
randomx_dataset* myDataset = randomx_alloc_dataset(flags);
|
||||
if (!myDataset) {
|
||||
printf("Dataset allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
const uint32_t numThreads = std::max(std::thread::hardware_concurrency(), 1U);
|
||||
const uint32_t numItems = randomx_dataset_item_count();
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(numThreads);
|
||||
|
||||
for (uint32_t i = 1; i < numThreads; ++i) {
|
||||
const uint32_t a = (numItems * i) / numThreads;
|
||||
const uint32_t b = (numItems * (i + 1)) / numThreads;
|
||||
|
||||
threads.emplace_back([myDataset, myCache, a, b]() { randomx_init_dataset(myDataset, myCache, a, b - a); });
|
||||
}
|
||||
randomx_init_dataset(myDataset, myCache, 0, numItems / numThreads);
|
||||
|
||||
for (std::thread& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
randomx_release_cache(myCache);
|
||||
|
||||
randomx_vm* myMachine = randomx_create_vm(flags, nullptr, myDataset);
|
||||
if (!myMachine) {
|
||||
printf("Failed to create a virtual machine");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(hash, 0, sizeof(hash));
|
||||
memcpy(hash, myInput, sizeof(myInput));
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
randomx_calculate_hash(myMachine, &hash, sizeof(hash), hash);
|
||||
}
|
||||
|
||||
char buf[RANDOMX_HASH_SIZE * 2 + 1] = {};
|
||||
p2pool::log::Stream s(buf);
|
||||
s << p2pool::log::hex_buf(hash, RANDOMX_HASH_SIZE) << '\0';
|
||||
|
||||
constexpr char expected_hash[] = "3b5ecc2bb14f467161a04fe476b541194fba82dbbbfc7c320961f922a0294dee";
|
||||
|
||||
if (memcmp(buf, expected_hash, RANDOMX_HASH_SIZE * 2) != 0) {
|
||||
printf("Invalid hash calculated: expected %s, got %s\n", expected_hash, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
randomx_destroy_vm(myMachine);
|
||||
randomx_release_dataset(myDataset);
|
||||
#endif
|
||||
|
||||
printf("Self-test passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
@@ -90,6 +172,15 @@ int main(int argc, char* argv[])
|
||||
p2pool_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "/version") || !strcmp(argv[i], "-v") || !strcmp(argv[i], "/v")) {
|
||||
p2pool_version();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "--test")) {
|
||||
return p2pool_test();
|
||||
}
|
||||
}
|
||||
|
||||
memory_tracking_start();
|
||||
@@ -113,7 +204,9 @@ int main(int argc, char* argv[])
|
||||
|
||||
p2pool::destroy_crypto_cache();
|
||||
|
||||
memory_tracking_stop();
|
||||
if (!memory_tracking_stop()) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
#include "common.h"
|
||||
|
||||
// Simple memory leak detector for Windows users, works best in RelWithDebInfo configuration.
|
||||
#if defined(_WIN32) && 0
|
||||
#if defined(_WIN32) && defined(DEV_TRACK_MEMORY) && defined(_MSC_VER) && !defined(NDEBUG)
|
||||
|
||||
#include "uv_util.h"
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
#include <iostream>
|
||||
|
||||
#include <DbgHelp.h>
|
||||
|
||||
@@ -87,7 +88,7 @@ uint32_t num_allocations = 0;
|
||||
uint64_t total_allocated = 0;
|
||||
uint32_t cur_allocation_index = 1;
|
||||
|
||||
void show_top_10()
|
||||
void show_top_10_allocations()
|
||||
{
|
||||
TrackedAllocation* buf = reinterpret_cast<TrackedAllocation*>(VirtualAlloc(nullptr, sizeof(TrackedAllocation) * N, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
if (!buf) {
|
||||
@@ -122,7 +123,8 @@ void show_top_10()
|
||||
|
||||
std::sort(buf, end, [](const auto& a, const auto& b) { return a.allocated_size > b.allocated_size; });
|
||||
|
||||
printf("%I64u total bytes allocated\n", total_allocated);
|
||||
printf("%I64u total bytes allocated\n\n", total_allocated);
|
||||
printf("Top 10 allocations:\n\n");
|
||||
|
||||
for (TrackedAllocation* p = buf; (p < buf + 10) && (p < end); ++p) {
|
||||
printf("%I64u bytes allocated at:\n", p->allocated_size);
|
||||
@@ -130,6 +132,8 @@ void show_top_10()
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
VirtualFree(buf, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
@@ -263,7 +267,8 @@ void* calloc_hook(size_t count, size_t size) noexcept
|
||||
|
||||
void memory_tracking_start()
|
||||
{
|
||||
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||
// Trigger std::ostream initialization to avoid reporting it as leaks
|
||||
std::cout << "Memory leak detection = " << 1 << std::endl;
|
||||
|
||||
using namespace p2pool;
|
||||
|
||||
@@ -272,7 +277,7 @@ void memory_tracking_start()
|
||||
track_memory = true;
|
||||
}
|
||||
|
||||
void memory_tracking_stop()
|
||||
bool memory_tracking_stop()
|
||||
{
|
||||
using namespace p2pool;
|
||||
|
||||
@@ -296,8 +301,11 @@ void memory_tracking_stop()
|
||||
if (total_leaks > 0) {
|
||||
printf("%I64u bytes leaked\n\n", total_leaks);
|
||||
}
|
||||
else {
|
||||
printf("No memory leaks detected\n\n");
|
||||
}
|
||||
|
||||
SymCleanup(h);
|
||||
return (total_leaks == 0);
|
||||
}
|
||||
|
||||
NOINLINE void* operator new(size_t n) { return p2pool::allocate(n); }
|
||||
@@ -313,7 +321,7 @@ NOINLINE void operator delete[](void* p, size_t) noexcept { p2pool::free_hook(p)
|
||||
// cppcheck-suppress functionStatic
|
||||
void memory_tracking_start() {}
|
||||
// cppcheck-suppress functionStatic
|
||||
void memory_tracking_stop() {}
|
||||
bool memory_tracking_stop() { return true; }
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
#include "mempool.h"
|
||||
#include "util.h"
|
||||
|
||||
static constexpr char log_category_prefix[] = "Mempool ";
|
||||
LOG_CATEGORY(Mempool)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
|
||||
+13
-4
@@ -28,7 +28,7 @@
|
||||
#include "p2p_server.h"
|
||||
#include <thread>
|
||||
|
||||
static constexpr char log_category_prefix[] = "Miner ";
|
||||
LOG_CATEGORY(Miner)
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
@@ -85,11 +85,11 @@ void Miner::print_status()
|
||||
const uint64_t hr = (dt > 0.0) ? static_cast<uint64_t>(hash_count / dt) : 0;
|
||||
|
||||
char shares_failed_buf[64] = {};
|
||||
log::Stream s(shares_failed_buf);
|
||||
|
||||
const uint32_t shares_found = m_sharesFound;
|
||||
const uint32_t shares_failed = m_sharesFailed;
|
||||
if (shares_failed) {
|
||||
log::Stream s(shares_failed_buf);
|
||||
s << log::Yellow() << "\nShares failed = " << shares_failed << log::NoColor();
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ void Miner::on_block(const BlockTemplate& block)
|
||||
m_nonceTimestamp = cur_ts;
|
||||
m_totalHashes += hash_count;
|
||||
|
||||
if (m_pool->api() && m_pool->params().m_localStats) {
|
||||
if (m_pool->api() && m_pool->params().m_localStats && !m_pool->stopped()) {
|
||||
const double block_reward_share_percent = m_pool->side_chain().get_reward_share(m_pool->params().m_wallet) * 100.0;
|
||||
|
||||
m_pool->api()->set(p2pool_api::Category::LOCAL, "miner",
|
||||
@@ -224,7 +224,16 @@ void Miner::run(WorkerData* data)
|
||||
job[index].set_nonce(static_cast<uint32_t>(full_nonce), static_cast<uint32_t>(full_nonce >> 32));
|
||||
|
||||
hash h;
|
||||
randomx_calculate_hash_next(vm, job[index].m_blob, job[index].m_blobSize, &h);
|
||||
try {
|
||||
randomx_calculate_hash_next(vm, job[index].m_blob, job[index].m_blobSize, &h);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(0, "Failed to calculate RandomX hash: exception \"" << e.what() << "\". Is your CPU/RAM unstable?" <<
|
||||
"\nFailed RandomX hash input: " << log::hex_buf(j.m_blob, j.m_blobSize));
|
||||
|
||||
// Make the result hash all FF's to fail difficulty checks
|
||||
memset(h.h, -1, HASH_SIZE);
|
||||
}
|
||||
|
||||
if (j.m_diff.check_pow(h)) {
|
||||
LOGINFO(0, log::Green() << "worker thread " << data->m_index << '/' << data->m_count << " found a mainchain block at height " << j.m_height << ", submitting it");
|
||||
|
||||
+451
-217
File diff suppressed because it is too large
Load Diff
+43
-23
@@ -18,7 +18,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.h"
|
||||
#include <list>
|
||||
#include "pool_block.h"
|
||||
#include <deque>
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
@@ -26,29 +27,35 @@ class p2pool;
|
||||
struct PoolBlock;
|
||||
class BlockCache;
|
||||
|
||||
static constexpr size_t P2P_BUF_SIZE = 128 * 1024;
|
||||
// Max block size plus BLOCK_RESPONSE header (5 bytes)
|
||||
static constexpr uint64_t P2P_BUF_SIZE = MAX_BLOCK_SIZE + (1 + sizeof(uint32_t));
|
||||
static_assert((P2P_BUF_SIZE & (P2P_BUF_SIZE - 1)) == 0, "P2P_BUF_SIZE is not a power of 2, fix MAX_BLOCK_SIZE");
|
||||
|
||||
static constexpr size_t PEER_LIST_RESPONSE_MAX_PEERS = 16;
|
||||
static constexpr int DEFAULT_P2P_PORT = 37889;
|
||||
static constexpr int DEFAULT_P2P_PORT_MINI = 37888;
|
||||
|
||||
static constexpr uint32_t PROTOCOL_VERSION_1_0 = 0x00010000UL;
|
||||
static constexpr uint32_t PROTOCOL_VERSION_1_1 = 0x00010001UL;
|
||||
static constexpr uint32_t PROTOCOL_VERSION_1_2 = 0x00010002UL;
|
||||
|
||||
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_1;
|
||||
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_2;
|
||||
|
||||
class P2PServer : public TCPServer<P2P_BUF_SIZE, P2P_BUF_SIZE>
|
||||
class P2PServer : public TCPServer
|
||||
{
|
||||
public:
|
||||
enum class MessageId {
|
||||
HANDSHAKE_CHALLENGE = 0,
|
||||
HANDSHAKE_SOLUTION = 1,
|
||||
LISTEN_PORT = 2,
|
||||
BLOCK_REQUEST = 3,
|
||||
BLOCK_RESPONSE = 4,
|
||||
BLOCK_BROADCAST = 5,
|
||||
PEER_LIST_REQUEST = 6,
|
||||
PEER_LIST_RESPONSE = 7,
|
||||
BLOCK_BROADCAST_COMPACT = 8,
|
||||
HANDSHAKE_CHALLENGE,
|
||||
HANDSHAKE_SOLUTION,
|
||||
LISTEN_PORT,
|
||||
BLOCK_REQUEST,
|
||||
BLOCK_RESPONSE,
|
||||
BLOCK_BROADCAST,
|
||||
PEER_LIST_REQUEST,
|
||||
PEER_LIST_RESPONSE,
|
||||
BLOCK_BROADCAST_COMPACT,
|
||||
BLOCK_NOTIFY,
|
||||
LAST = BLOCK_NOTIFY,
|
||||
};
|
||||
|
||||
explicit P2PServer(p2pool *pool);
|
||||
@@ -101,19 +108,22 @@ public:
|
||||
void on_after_handshake(uint8_t* &p);
|
||||
bool on_listen_port(const uint8_t* buf);
|
||||
bool on_block_request(const uint8_t* buf);
|
||||
bool on_block_response(const uint8_t* buf, uint32_t size, const hash& expected_id);
|
||||
bool on_block_response(const uint8_t* buf, uint32_t size, uint64_t expected_id);
|
||||
bool on_block_broadcast(const uint8_t* buf, uint32_t size, bool compact);
|
||||
bool on_peer_list_request(const uint8_t* buf);
|
||||
void on_peer_list_response(const uint8_t* buf);
|
||||
void on_block_notify(const uint8_t* buf);
|
||||
|
||||
bool handle_incoming_block_async(const PoolBlock* block, uint64_t max_time_delta = 0);
|
||||
void handle_incoming_block(p2pool* pool, PoolBlock& block, const uint32_t reset_counter, const raw_ip& addr, std::vector<hash>& missing_blocks);
|
||||
void post_handle_incoming_block(const uint32_t reset_counter, std::vector<hash>& missing_blocks);
|
||||
void handle_incoming_block(p2pool* pool, PoolBlock& block, std::vector<hash>& missing_blocks, bool& result);
|
||||
void post_handle_incoming_block(p2pool* pool, const PoolBlock& block, const uint32_t reset_counter, bool is_v6, const raw_ip& addr, std::vector<hash>& missing_blocks, const bool result);
|
||||
|
||||
bool is_good() const { return m_handshakeComplete && !m_handshakeInvalid && (m_listenPort >= 0); }
|
||||
|
||||
const char* software_name() const;
|
||||
|
||||
alignas(8) char m_p2pReadBuf[P2P_BUF_SIZE];
|
||||
|
||||
uint64_t m_peerId;
|
||||
uint64_t m_connectedTime;
|
||||
uint64_t m_broadcastMaxHeight;
|
||||
@@ -125,26 +135,25 @@ public:
|
||||
bool m_handshakeInvalid;
|
||||
int m_listenPort;
|
||||
|
||||
uint32_t m_fastPeerListRequestCount;
|
||||
uint64_t m_prevIncomingPeerListRequest;
|
||||
uint64_t m_prevPeersSent;
|
||||
uint64_t m_nextOutgoingPeerListRequest;
|
||||
std::chrono::high_resolution_clock::time_point m_lastPeerListRequestTime;
|
||||
int m_peerListPendingRequests;
|
||||
|
||||
uint32_t m_protocolVersion;
|
||||
uint32_t m_SoftwareVersion;
|
||||
uint32_t m_SoftwareID;
|
||||
SoftwareID m_SoftwareID;
|
||||
|
||||
int64_t m_pingTime;
|
||||
|
||||
std::list<hash> m_blockPendingRequests;
|
||||
std::deque<uint64_t> m_blockPendingRequests;
|
||||
|
||||
uint64_t m_lastAlive;
|
||||
uint64_t m_lastBroadcastTimestamp;
|
||||
uint64_t m_lastBlockrequestTimestamp;
|
||||
|
||||
hash m_broadcastedHashes[8];
|
||||
std::atomic<uint32_t> m_broadcastedHashesIndex{ 0 };
|
||||
uint32_t m_broadcastedHashesIndex;
|
||||
};
|
||||
|
||||
void broadcast(const PoolBlock& block, const PoolBlock* parent);
|
||||
@@ -166,7 +175,13 @@ public:
|
||||
int deserialize_block(const uint8_t* buf, uint32_t size, bool compact, uint64_t received_timestamp);
|
||||
const PoolBlock* get_block() const { return m_block; }
|
||||
|
||||
const PoolBlock* find_block(const hash& id) const;
|
||||
|
||||
void check_for_updates(bool forced = false) const;
|
||||
|
||||
private:
|
||||
const char* get_log_category() const override;
|
||||
|
||||
p2pool* m_pool;
|
||||
BlockCache* m_cache;
|
||||
bool m_cacheLoaded;
|
||||
@@ -183,7 +198,7 @@ private:
|
||||
|
||||
void flush_cache();
|
||||
void download_missing_blocks();
|
||||
void check_zmq();
|
||||
void check_host();
|
||||
void check_block_template();
|
||||
void update_peer_connections();
|
||||
void update_peer_list();
|
||||
@@ -193,7 +208,7 @@ private:
|
||||
void load_peer_list();
|
||||
void load_monerod_peer_list();
|
||||
void update_peer_in_list(bool is_v6, const raw_ip& ip, int port);
|
||||
void remove_peer_from_list(P2PClient* client);
|
||||
void remove_peer_from_list(const P2PClient* client);
|
||||
void remove_peer_from_list(const raw_ip& ip);
|
||||
|
||||
std::mt19937_64 m_rng;
|
||||
@@ -213,6 +228,8 @@ private:
|
||||
|
||||
struct Peer
|
||||
{
|
||||
void normalize();
|
||||
|
||||
bool m_isV6;
|
||||
raw_ip m_addr;
|
||||
int m_port;
|
||||
@@ -241,8 +258,10 @@ private:
|
||||
|
||||
bool m_lookForMissingBlocks;
|
||||
unordered_set<std::pair<uint64_t, uint64_t>> m_missingBlockRequests;
|
||||
unordered_set<uint64_t> m_blockNotifyRequests;
|
||||
|
||||
P2PClient* m_fastestPeer;
|
||||
std::atomic<bool> m_newP2PoolVersionDetected;
|
||||
|
||||
static void on_broadcast(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->on_broadcast(); }
|
||||
void on_broadcast();
|
||||
@@ -253,6 +272,7 @@ private:
|
||||
|
||||
static void on_connect_to_peers(uv_async_t* handle);
|
||||
|
||||
uv_mutex_t m_showPeersLock;
|
||||
uv_async_t m_showPeersAsync;
|
||||
|
||||
static void on_show_peers(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->show_peers(); }
|
||||
|
||||
+167
-93
@@ -40,7 +40,8 @@
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
|
||||
constexpr char log_category_prefix[] = "P2Pool ";
|
||||
LOG_CATEGORY(P2Pool)
|
||||
|
||||
constexpr int BLOCK_HEADERS_REQUIRED = 720;
|
||||
|
||||
constexpr uint64_t SEEDHASH_EPOCH_BLOCKS = 2048;
|
||||
@@ -69,36 +70,15 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!p->m_wallet.valid()) {
|
||||
LOGERR(1, "Invalid wallet address. Try \"p2pool --help\".");
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
m_hostStr = p->m_host;
|
||||
|
||||
if (p->m_socks5Proxy.empty()) {
|
||||
if (p->m_dns) {
|
||||
bool is_v6;
|
||||
if (!resolve_host(p->m_host, is_v6)) {
|
||||
LOGERR(1, "resolve_host failed for " << p->m_host);
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
else if (p->m_host.find_first_not_of("0123456789.:") != std::string::npos) {
|
||||
LOGERR(1, "Can't resolve hostname " << p->m_host << " with DNS disabled");
|
||||
for (Params::Host& h : p->m_hosts) {
|
||||
if (!h.init_display_name(*p)) {
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const bool changed = (p->m_host != m_hostStr);
|
||||
const std::string rpc_port = ':' + std::to_string(p->m_rpcPort);
|
||||
const std::string zmq_port = ":ZMQ:" + std::to_string(p->m_zmqPort);
|
||||
m_hostStr += rpc_port + zmq_port;
|
||||
if (changed) {
|
||||
m_hostStr += " (" + p->m_host + ')';
|
||||
}
|
||||
}
|
||||
m_currentHostIndex = 0;
|
||||
|
||||
m_hostPing.resize(p->m_hosts.size());
|
||||
|
||||
hash pub, sec, eph_public_key;
|
||||
generate_keys(pub, sec);
|
||||
@@ -139,15 +119,16 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
}
|
||||
m_stopAsync.data = this;
|
||||
|
||||
err = uv_async_init(uv_default_loop_checked(), &m_restartZMQAsync, on_restart_zmq);
|
||||
err = uv_async_init(uv_default_loop_checked(), &m_reconnectToHostAsync, on_reconnect_to_host);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
|
||||
throw std::exception();
|
||||
}
|
||||
m_restartZMQAsync.data = this;
|
||||
m_reconnectToHostAsync.data = this;
|
||||
|
||||
uv_rwlock_init_checked(&m_mainchainLock);
|
||||
uv_rwlock_init_checked(&m_minerDataLock);
|
||||
uv_rwlock_init_checked(&m_ZMQReaderLock);
|
||||
uv_mutex_init_checked(&m_foundBlocksLock);
|
||||
#ifdef WITH_RANDOMX
|
||||
uv_mutex_init_checked(&m_minerLock);
|
||||
@@ -206,6 +187,7 @@ p2pool::~p2pool()
|
||||
|
||||
uv_rwlock_destroy(&m_mainchainLock);
|
||||
uv_rwlock_destroy(&m_minerDataLock);
|
||||
uv_rwlock_destroy(&m_ZMQReaderLock);
|
||||
uv_mutex_destroy(&m_foundBlocksLock);
|
||||
#ifdef WITH_RANDOMX
|
||||
uv_mutex_destroy(&m_minerLock);
|
||||
@@ -220,6 +202,47 @@ p2pool::~p2pool()
|
||||
delete m_params;
|
||||
}
|
||||
|
||||
void p2pool::update_host_ping(const std::string& display_name, double ping)
|
||||
{
|
||||
if (ping < 100) {
|
||||
LOGINFO(1, display_name << " ping is " << ping << " ms");
|
||||
}
|
||||
else {
|
||||
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;
|
||||
|
||||
for (size_t i = 0, n = v.size(); i < n; ++i) {
|
||||
if (v[i].m_displayName == display_name) {
|
||||
m_hostPing[i] = ping;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
char buf[64] = {};
|
||||
if (m_hostPing[i] > 0.0) {
|
||||
log::Stream s(buf);
|
||||
s << " (" << m_hostPing[i] << " ms)";
|
||||
}
|
||||
|
||||
if (h.m_displayName == host.m_displayName) {
|
||||
LOGINFO(0, log::LightCyan() << "-> " << h.m_displayName << static_cast<const char*>(buf));
|
||||
}
|
||||
else {
|
||||
LOGINFO(0, " " << h.m_displayName << static_cast<const char*>(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool p2pool::calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result, bool force_light_mode)
|
||||
{
|
||||
return m_hasher->calculate(data, size, height, seed, result, force_light_mode);
|
||||
@@ -297,17 +320,15 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
{
|
||||
WriteLock lock(m_mainchainLock);
|
||||
|
||||
m_mainchainByHeight[data.height].difficulty = data.difficulty;
|
||||
ChainMain& c0 = m_mainchainByHeight[data.height];
|
||||
c0.height = data.height;
|
||||
c0.difficulty = data.difficulty;
|
||||
|
||||
ChainMain& c = m_mainchainByHeight[data.height - 1];
|
||||
c.height = data.height - 1;
|
||||
c.id = data.prev_id;
|
||||
ChainMain& c1 = m_mainchainByHeight[data.height - 1];
|
||||
c1.height = data.height - 1;
|
||||
c1.id = data.prev_id;
|
||||
|
||||
// timestamp and reward is unknown here
|
||||
c.timestamp = 0;
|
||||
c.reward = 0;
|
||||
|
||||
m_mainchainByHash[c.id] = c;
|
||||
m_mainchainByHash[c1.id] = c1;
|
||||
|
||||
cleanup_mainchain_data(data.height);
|
||||
}
|
||||
@@ -321,8 +342,11 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
m_updateSeed = true;
|
||||
update_median_timestamp();
|
||||
|
||||
const Params::Host& host = current_host();
|
||||
|
||||
LOGINFO(2,
|
||||
"new miner data\n---------------------------------------------------------------------------------------------------------------" <<
|
||||
"\nhost = " << host.m_displayName <<
|
||||
"\nmajor_version = " << data.major_version <<
|
||||
"\nheight = " << data.height <<
|
||||
"\nprev_id = " << log::LightBlue() << data.prev_id << log::NoColor() <<
|
||||
@@ -370,15 +394,15 @@ void p2pool::handle_miner_data(MinerData& data)
|
||||
log::Stream s(buf);
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << h << "}}\0";
|
||||
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, buf, m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, h](const char* data, size_t size)
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, h](const char* data, size_t size, double)
|
||||
{
|
||||
ChainMain block;
|
||||
if (!parse_block_header(data, size, block)) {
|
||||
LOGERR(1, "couldn't download block header for height " << h);
|
||||
}
|
||||
},
|
||||
[h](const char* data, size_t size)
|
||||
[h](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "couldn't download block header for height " << h << ", error " << log::const_buf(data, size));
|
||||
@@ -438,11 +462,13 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
|
||||
", reward = " << log::Gray() << log::XMRAmount(data.reward));
|
||||
|
||||
if (!sidechain_id.empty()) {
|
||||
PoolBlock* block = side_chain().find_block(sidechain_id);
|
||||
const 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 Wallet& w = params().m_wallet;
|
||||
|
||||
const char* who = (block->m_minerWallet == w) ? "you" : "someone else in this p2pool";
|
||||
LOGINFO(0, log::LightGreen() << "BLOCK FOUND: main chain block at height " << data.height << " was mined by " << who << BLOCK_FOUND);
|
||||
|
||||
const uint64_t payout = block->get_payout(w);
|
||||
if (payout) {
|
||||
LOGINFO(0, log::LightCyan() << "Your wallet " << log::LightGreen() << w << log::LightCyan() << " got a payout of " << log::LightGreen() << log::XMRAmount(payout) << log::LightCyan() << " in block " << log::LightGreen() << data.height);
|
||||
@@ -526,7 +552,7 @@ void p2pool::on_stop(uv_async_t* async)
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_submitBlockAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_blockTemplateAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_stopAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_restartZMQAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&pool->m_reconnectToHostAsync), nullptr);
|
||||
|
||||
init_signals(pool, false);
|
||||
|
||||
@@ -601,11 +627,13 @@ void p2pool::submit_block() const
|
||||
}
|
||||
request.append("\"]}");
|
||||
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, request, m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[height, diff, template_id, nonce, extra_nonce, sidechain_id, is_external](const char* data, size_t size)
|
||||
const Params::Host& host = current_host();
|
||||
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, request, host.m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[height, diff, template_id, nonce, extra_nonce, sidechain_id, is_external](const char* data, size_t size, double)
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
if (doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size).HasParseError() || !doc.IsObject()) {
|
||||
if (doc.Parse(data, size).HasParseError() || !doc.IsObject()) {
|
||||
LOGERR(0, "submit_block: invalid JSON response from daemon");
|
||||
return;
|
||||
}
|
||||
@@ -646,7 +674,7 @@ void p2pool::submit_block() const
|
||||
|
||||
LOGWARN(0, "submit_block: daemon sent unrecognizable reply: " << log::const_buf(data, size));
|
||||
},
|
||||
[is_external](const char* data, size_t size)
|
||||
[is_external](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
if (is_external) {
|
||||
@@ -712,14 +740,16 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
char buf[log::Stream::BUF_SIZE + 1] = {};
|
||||
log::Stream s(buf);
|
||||
|
||||
const Params::Host& host = current_host();
|
||||
|
||||
// First download 2 RandomX seeds
|
||||
const uint64_t seed_heights[2] = { prev_seed_height, seed_height };
|
||||
for (uint64_t height : seed_heights) {
|
||||
s.m_pos = 0;
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_header_by_height\",\"params\":{\"height\":" << height << "}}\0";
|
||||
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, buf, m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, prev_seed_height, height](const char* data, size_t size)
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, prev_seed_height, height](const char* data, size_t size, double)
|
||||
{
|
||||
ChainMain block;
|
||||
if (parse_block_header(data, size, block)) {
|
||||
@@ -733,7 +763,7 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
PANIC_STOP();
|
||||
}
|
||||
},
|
||||
[height](const char* data, size_t size)
|
||||
[height](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "fatal error: couldn't download block header for seed height " << height << ", error " << log::const_buf(data, size));
|
||||
@@ -747,8 +777,8 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
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(m_params->m_host, m_params->m_rpcPort, buf, m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, start_height, current_height](const char* data, size_t size)
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this, start_height, current_height, host](const char* data, size_t size, double)
|
||||
{
|
||||
if (parse_block_headers_range(data, size) == current_height - start_height) {
|
||||
update_median_timestamp();
|
||||
@@ -760,15 +790,33 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
start_mining(m_params->m_minerThreads);
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
m_ZMQReader = new ZMQReader(m_params->m_host, m_params->m_zmqPort, m_params->m_socks5Proxy, this);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(1, "Couldn't start ZMQ reader: exception " << e.what());
|
||||
PANIC_STOP();
|
||||
{
|
||||
WriteLock lock(m_ZMQReaderLock);
|
||||
|
||||
try {
|
||||
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) {
|
||||
LOGERR(1, "Couldn't start ZMQ reader: exception " << e.what());
|
||||
PANIC_STOP();
|
||||
}
|
||||
}
|
||||
|
||||
api_update_network_stats();
|
||||
get_miner_data();
|
||||
|
||||
// Get ping times for all other 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,
|
||||
[this, name](const char*, size_t, double tcp_ping) { update_host_ping(name, tcp_ping); },
|
||||
[](const char*, size_t, double) {});
|
||||
}
|
||||
}
|
||||
|
||||
m_startupFinished = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -776,7 +824,7 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
download_block_headers(current_height);
|
||||
}
|
||||
},
|
||||
[this, start_height, current_height](const char* data, size_t size)
|
||||
[this, start_height, current_height](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "Couldn't download block headers for heights " << start_height << " - " << current_height - 1 << ", error " << log::const_buf(data, size));
|
||||
@@ -802,13 +850,13 @@ bool p2pool::get_timestamps(uint64_t (×tamps)[TIMESTAMP_WINDOW]) const
|
||||
{
|
||||
ReadLock lock(m_mainchainLock);
|
||||
|
||||
if (m_mainchainByHeight.size() <= TIMESTAMP_WINDOW) {
|
||||
if (m_mainchainByHeight.size() < TIMESTAMP_WINDOW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = m_mainchainByHeight.end();
|
||||
|
||||
for (int i = 0; (i < TIMESTAMP_WINDOW) && (it != m_mainchainByHeight.begin()); ++i) {
|
||||
for (int i = 0; i < TIMESTAMP_WINDOW; ++i) {
|
||||
--it;
|
||||
timestamps[i] = it->second.timestamp;
|
||||
}
|
||||
@@ -855,17 +903,20 @@ void p2pool::stratum_on_block()
|
||||
|
||||
void p2pool::get_info()
|
||||
{
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_info\"}", m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this](const char* data, size_t size)
|
||||
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,
|
||||
[this](const char* data, size_t size, double)
|
||||
{
|
||||
parse_get_info_rpc(data, size);
|
||||
},
|
||||
[this](const char* data, size_t size)
|
||||
[this, host](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGWARN(1, "get_info RPC request failed: error " << log::const_buf(data, size) << ", trying again in 1 second");
|
||||
LOGWARN(1, "get_info RPC request to host " << host.m_displayName << " failed: error " << log::const_buf(data, size) << ", trying again in 1 second");
|
||||
if (!m_stopped) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
switch_host();
|
||||
get_info();
|
||||
}
|
||||
}
|
||||
@@ -874,7 +925,7 @@ void p2pool::get_info()
|
||||
|
||||
void p2pool::load_found_blocks()
|
||||
{
|
||||
if (!m_api) {
|
||||
if (!m_api || m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -917,7 +968,7 @@ void p2pool::parse_get_info_rpc(const char* data, size_t size)
|
||||
}
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size);
|
||||
doc.Parse(data, size);
|
||||
|
||||
if (!doc.IsObject() || !doc.HasMember("result")) {
|
||||
LOGWARN(1, "get_info RPC response is invalid (\"result\" not found), trying again in 1 second");
|
||||
@@ -968,12 +1019,14 @@ void p2pool::parse_get_info_rpc(const char* data, size_t size)
|
||||
|
||||
void p2pool::get_version()
|
||||
{
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_version\"}", m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this](const char* data, size_t size)
|
||||
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,
|
||||
[this](const char* data, size_t size, double)
|
||||
{
|
||||
parse_get_version_rpc(data, size);
|
||||
},
|
||||
[this](const char* data, size_t size)
|
||||
[this](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGWARN(1, "get_version RPC request failed: error " << log::const_buf(data, size) << ", trying again in 1 second");
|
||||
@@ -992,7 +1045,7 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
|
||||
}
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size);
|
||||
doc.Parse(data, size);
|
||||
|
||||
if (!doc.IsObject() || !doc.HasMember("result")) {
|
||||
LOGWARN(1, "get_version RPC response is invalid (\"result\" not found), trying again in 1 second");
|
||||
@@ -1036,24 +1089,28 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
|
||||
get_miner_data();
|
||||
}
|
||||
|
||||
void p2pool::get_miner_data()
|
||||
void p2pool::get_miner_data(bool retry)
|
||||
{
|
||||
if (m_getMinerDataPending) {
|
||||
return;
|
||||
}
|
||||
m_getMinerDataPending = true;
|
||||
|
||||
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}", m_params->m_rpcLogin, m_params->m_socks5Proxy,
|
||||
[this](const char* data, size_t size)
|
||||
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,
|
||||
[this, host](const char* data, size_t size, double tcp_ping)
|
||||
{
|
||||
parse_get_miner_data_rpc(data, size);
|
||||
update_host_ping(host.m_displayName, tcp_ping);
|
||||
},
|
||||
[this](const char* data, size_t size)
|
||||
[this, host, retry](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGWARN(1, "get_miner_data RPC request failed: error " << log::const_buf(data, size) << ", trying again in 1 second");
|
||||
if (!m_stopped) {
|
||||
LOGWARN(1, "get_miner_data RPC request to host " << host.m_displayName << " failed: error " << log::const_buf(data, size) << (retry ? ", trying again in 1 second" : ""));
|
||||
if (!m_stopped && retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
m_getMinerDataPending = false;
|
||||
get_miner_data();
|
||||
}
|
||||
}
|
||||
@@ -1078,7 +1135,7 @@ void p2pool::parse_get_miner_data_rpc(const char* data, size_t size)
|
||||
m_getMinerDataHash = h;
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size);
|
||||
doc.Parse(data, size);
|
||||
|
||||
if (!doc.IsObject() || !doc.HasMember("result")) {
|
||||
LOGWARN(1, "get_miner_data RPC response is invalid, skipping it");
|
||||
@@ -1128,7 +1185,7 @@ void p2pool::parse_get_miner_data_rpc(const char* data, size_t size)
|
||||
bool p2pool::parse_block_header(const char* data, size_t size, ChainMain& c)
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
if (doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size).HasParseError() || !doc.IsObject()) {
|
||||
if (doc.Parse(data, size).HasParseError() || !doc.IsObject()) {
|
||||
LOGERR(1, "parse_block_header: invalid JSON response from daemon");
|
||||
return false;
|
||||
}
|
||||
@@ -1170,7 +1227,7 @@ bool p2pool::parse_block_header(const char* data, size_t size, ChainMain& c)
|
||||
uint32_t p2pool::parse_block_headers_range(const char* data, size_t size)
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
if (doc.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseTrailingCommasFlag>(data, size).HasParseError() || !doc.IsObject()) {
|
||||
if (doc.Parse(data, size).HasParseError() || !doc.IsObject()) {
|
||||
LOGERR(1, "parse_block_headers_range: invalid JSON response from daemon");
|
||||
return 0;
|
||||
}
|
||||
@@ -1220,7 +1277,7 @@ uint32_t p2pool::parse_block_headers_range(const char* data, size_t size)
|
||||
|
||||
void p2pool::api_update_network_stats()
|
||||
{
|
||||
if (!m_api) {
|
||||
if (!m_api || m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1251,7 +1308,7 @@ void p2pool::api_update_network_stats()
|
||||
|
||||
void p2pool::api_update_pool_stats()
|
||||
{
|
||||
if (!m_api) {
|
||||
if (!m_api || m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1303,7 +1360,7 @@ void p2pool::api_update_pool_stats()
|
||||
|
||||
void p2pool::api_update_stats_mod()
|
||||
{
|
||||
if (!m_api) {
|
||||
if (!m_api || m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1396,7 +1453,7 @@ void p2pool::cleanup_mainchain_data(uint64_t height)
|
||||
|
||||
void p2pool::api_update_block_found(const ChainMain* data, const PoolBlock* block)
|
||||
{
|
||||
if (!m_api) {
|
||||
if (!m_api || m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1562,33 +1619,47 @@ void p2pool::stop()
|
||||
|
||||
bool p2pool::zmq_running() const
|
||||
{
|
||||
ReadLock lock(m_ZMQReaderLock);
|
||||
return m_ZMQReader && m_ZMQReader->is_running();
|
||||
}
|
||||
|
||||
void p2pool::restart_zmq()
|
||||
const Params::Host& p2pool::switch_host()
|
||||
{
|
||||
// If p2pool is stopped, m_restartZMQAsync is most likely already closed
|
||||
const std::vector<Params::Host>& v = m_params->m_hosts;
|
||||
return v[++m_currentHostIndex % v.size()];
|
||||
}
|
||||
|
||||
void p2pool::reconnect_to_host()
|
||||
{
|
||||
// If p2pool is stopped, m_reconnectToHostAsync is most likely already closed
|
||||
if (m_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_main_thread()) {
|
||||
uv_async_send(&m_restartZMQAsync);
|
||||
uv_async_send(&m_reconnectToHostAsync);
|
||||
return;
|
||||
}
|
||||
|
||||
get_miner_data();
|
||||
const Params::Host& new_host = switch_host();
|
||||
|
||||
WriteLock lock(m_ZMQReaderLock);
|
||||
|
||||
delete m_ZMQReader;
|
||||
m_ZMQReader = nullptr;
|
||||
|
||||
try {
|
||||
m_ZMQReader = new ZMQReader(m_params->m_host, m_params->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;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(1, "Couldn't restart ZMQ reader: exception " << e.what());
|
||||
}
|
||||
|
||||
if (m_ZMQReader) {
|
||||
get_miner_data(false);
|
||||
}
|
||||
}
|
||||
|
||||
int p2pool::run()
|
||||
@@ -1613,11 +1684,14 @@ int p2pool::run()
|
||||
load_found_blocks();
|
||||
const int rc = uv_run(uv_default_loop_checked(), UV_RUN_DEFAULT);
|
||||
LOGINFO(1, "uv_run exited, result = " << rc);
|
||||
|
||||
WriteLock lock(m_ZMQReaderLock);
|
||||
|
||||
delete m_ZMQReader;
|
||||
m_ZMQReader = nullptr;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
const char* s = e.what();
|
||||
LOGERR(1, "exception " << s);
|
||||
LOGERR(1, "exception " << e.what());
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
|
||||
+24
-7
@@ -18,11 +18,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "uv_util.h"
|
||||
#include "params.h"
|
||||
#include <map>
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
struct Params;
|
||||
class RandomX_Hasher_Base;
|
||||
class BlockTemplate;
|
||||
class Mempool;
|
||||
@@ -46,11 +46,19 @@ public:
|
||||
bool stopped() const { return m_stopped; }
|
||||
void stop();
|
||||
|
||||
const std::string& host_str() const { return m_hostStr; }
|
||||
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;
|
||||
return v[m_currentHostIndex % v.size()];
|
||||
}
|
||||
|
||||
void update_host_ping(const std::string& display_name, double ping);
|
||||
void print_hosts() const;
|
||||
|
||||
FORCEINLINE MinerData miner_data() const
|
||||
{
|
||||
ReadLock lock(m_minerDataLock);
|
||||
@@ -98,23 +106,29 @@ public:
|
||||
bool zmq_running() const;
|
||||
uint64_t zmq_last_active() const { return m_zmqLastActive; }
|
||||
uint64_t start_time() const { return m_startTime; }
|
||||
void restart_zmq();
|
||||
void reconnect_to_host();
|
||||
|
||||
bool startup_finished() const { return m_startupFinished.load(); }
|
||||
|
||||
private:
|
||||
p2pool(const p2pool&) = delete;
|
||||
p2pool(p2pool&&) = delete;
|
||||
|
||||
const Params::Host& switch_host();
|
||||
|
||||
static void on_submit_block(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->submit_block(); }
|
||||
static void on_update_block_template(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->update_block_template(); }
|
||||
static void on_stop(uv_async_t*);
|
||||
static void on_restart_zmq(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->restart_zmq(); }
|
||||
static void on_reconnect_to_host(uv_async_t* async) { reinterpret_cast<p2pool*>(async->data)->reconnect_to_host(); }
|
||||
|
||||
void submit_block() const;
|
||||
|
||||
std::atomic<bool> m_stopped;
|
||||
|
||||
std::string m_hostStr;
|
||||
const Params* m_params;
|
||||
std::vector<double> m_hostPing;
|
||||
|
||||
std::atomic<uint32_t> m_currentHostIndex;
|
||||
|
||||
p2pool_api* m_api;
|
||||
SideChain* m_sideChain;
|
||||
@@ -143,7 +157,7 @@ private:
|
||||
void get_version();
|
||||
void parse_get_version_rpc(const char* data, size_t size);
|
||||
|
||||
void get_miner_data();
|
||||
void get_miner_data(bool retry = true);
|
||||
void parse_get_miner_data_rpc(const char* data, size_t size);
|
||||
|
||||
bool parse_block_header(const char* data, size_t size, ChainMain& c);
|
||||
@@ -179,6 +193,8 @@ private:
|
||||
StratumServer* m_stratumServer = nullptr;
|
||||
P2PServer* m_p2pServer = nullptr;
|
||||
|
||||
std::atomic<bool> m_startupFinished{ false };
|
||||
|
||||
#ifdef WITH_RANDOMX
|
||||
uv_mutex_t m_minerLock;
|
||||
Miner* m_miner = nullptr;
|
||||
@@ -205,8 +221,9 @@ private:
|
||||
|
||||
std::atomic<uint64_t> m_zmqLastActive;
|
||||
uint64_t m_startTime;
|
||||
uv_async_t m_restartZMQAsync;
|
||||
uv_async_t m_reconnectToHostAsync;
|
||||
|
||||
mutable uv_rwlock_t m_ZMQReaderLock;
|
||||
ZMQReader* m_ZMQReader = nullptr;
|
||||
|
||||
hash m_getMinerDataHash;
|
||||
|
||||
+22
-8
@@ -24,7 +24,7 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
static constexpr char log_category_prefix[] = "P2Pool API ";
|
||||
LOG_CATEGORY(P2Pool API)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
@@ -100,14 +100,24 @@ void p2pool_api::create_dir(const std::string& path)
|
||||
|
||||
void p2pool_api::on_stop()
|
||||
{
|
||||
MutexLock lock(m_dumpDataLock);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_dumpToFileAsync), nullptr);
|
||||
}
|
||||
|
||||
void p2pool_api::dump_to_file_async_internal(Category category, const char* filename, DumpFileCallbackBase&& callback)
|
||||
void p2pool_api::dump_to_file_async_internal(Category category, const char* filename, Callback<void, log::Stream&>::Base&& callback)
|
||||
{
|
||||
std::vector<char> buf(16384);
|
||||
std::vector<char> buf(1024);
|
||||
log::Stream s(buf.data(), buf.size());
|
||||
callback(s);
|
||||
|
||||
// If the buffer was too small, try again with big enough buffer
|
||||
if (s.m_spilled) {
|
||||
// Assume that the second call will use no more than 2X bytes
|
||||
buf.resize((static_cast<ptrdiff_t>(s.m_pos) + s.m_spilled) * 2 + 1);
|
||||
s.reset(buf.data(), buf.size());
|
||||
callback(s);
|
||||
}
|
||||
|
||||
buf.resize(s.m_pos);
|
||||
|
||||
std::string path;
|
||||
@@ -119,10 +129,8 @@ void p2pool_api::dump_to_file_async_internal(Category category, const char* file
|
||||
case Category::LOCAL: path = m_localPath + filename; break;
|
||||
}
|
||||
|
||||
{
|
||||
MutexLock lock(m_dumpDataLock);
|
||||
m_dumpData[path] = std::move(buf);
|
||||
}
|
||||
MutexLock lock(m_dumpDataLock);
|
||||
m_dumpData[path] = std::move(buf);
|
||||
|
||||
if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_dumpToFileAsync))) {
|
||||
uv_async_send(&m_dumpToFileAsync);
|
||||
@@ -137,8 +145,14 @@ void p2pool_api::dump_to_file()
|
||||
data = std::move(m_dumpData);
|
||||
}
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1];
|
||||
buf[0] = '\0';
|
||||
|
||||
for (auto& it : data) {
|
||||
DumpFileWork* work = new DumpFileWork{ {}, 0, it.first, it.first + std::to_string(m_counter), std::move(it.second) };
|
||||
log::Stream s(buf);
|
||||
s << it.first << m_counter << '\0';
|
||||
|
||||
DumpFileWork* work = new DumpFileWork{ {}, 0, it.first, buf, std::move(it.second) };
|
||||
work->req.data = work;
|
||||
++m_counter;
|
||||
|
||||
|
||||
+2
-20
@@ -38,7 +38,7 @@ public:
|
||||
void on_stop();
|
||||
|
||||
template<typename T>
|
||||
void set(Category category, const char* filename, T&& callback) { dump_to_file_async_internal(category, filename, DumpFileCallback<T>(std::move(callback))); }
|
||||
void set(Category category, const char* filename, T&& callback) { dump_to_file_async_internal(category, filename, Callback<void, log::Stream&>::Derived<T>(std::move(callback))); }
|
||||
|
||||
private:
|
||||
void create_dir(const std::string& path);
|
||||
@@ -54,25 +54,7 @@ private:
|
||||
std::vector<char> buf;
|
||||
};
|
||||
|
||||
struct DumpFileCallbackBase
|
||||
{
|
||||
virtual ~DumpFileCallbackBase() {}
|
||||
virtual void operator()(log::Stream&) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DumpFileCallback : public DumpFileCallbackBase
|
||||
{
|
||||
explicit FORCEINLINE DumpFileCallback(T&& callback) : m_callback(std::move(callback)) {}
|
||||
void operator()(log::Stream& s) override { m_callback(s); }
|
||||
|
||||
private:
|
||||
DumpFileCallback& operator=(DumpFileCallback&&) = delete;
|
||||
|
||||
T m_callback;
|
||||
};
|
||||
|
||||
void dump_to_file_async_internal(Category category, const char* filename, DumpFileCallbackBase&& callback);
|
||||
void dump_to_file_async_internal(Category category, const char* filename, Callback<void, log::Stream&>::Base&& callback);
|
||||
void dump_to_file();
|
||||
static void on_fs_open(uv_fs_t* req);
|
||||
static void on_fs_write(uv_fs_t* req);
|
||||
|
||||
+82
-6
@@ -20,27 +20,47 @@
|
||||
#include "stratum_server.h"
|
||||
#include "p2p_server.h"
|
||||
|
||||
LOG_CATEGORY(Params)
|
||||
|
||||
void p2pool_usage();
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
Params::Params(int argc, char* argv[])
|
||||
Params::Params(int argc, char* const argv[])
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
bool ok = false;
|
||||
|
||||
if ((strcmp(argv[i], "--host") == 0) && (i + 1 < argc)) {
|
||||
m_host = argv[++i];
|
||||
const char* address = argv[++i];
|
||||
|
||||
if (m_hosts.empty()) {
|
||||
m_hosts.emplace_back(Host());
|
||||
m_hosts.back().m_address = address;
|
||||
}
|
||||
else {
|
||||
const Host& h = m_hosts.back();
|
||||
m_hosts.emplace_back(address, h.m_rpcPort, h.m_zmqPort, "");
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--rpc-port") == 0) && (i + 1 < argc)) {
|
||||
m_rpcPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
if (m_hosts.empty()) {
|
||||
m_hosts.emplace_back(Host());
|
||||
}
|
||||
|
||||
m_hosts.back().m_rpcPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--zmq-port") == 0) && (i + 1 < argc)) {
|
||||
m_zmqPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
if (m_hosts.empty()) {
|
||||
m_hosts.emplace_back(Host());
|
||||
}
|
||||
|
||||
m_hosts.back().m_zmqPort = std::min(std::max(strtoul(argv[++i], nullptr, 10), 1UL), 65535UL);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -133,7 +153,11 @@ Params::Params(int argc, char* argv[])
|
||||
}
|
||||
|
||||
if ((strcmp(argv[i], "--rpc-login") == 0) && (i + 1 < argc)) {
|
||||
m_rpcLogin = argv[++i];
|
||||
if (m_hosts.empty()) {
|
||||
m_hosts.emplace_back(Host());
|
||||
}
|
||||
|
||||
m_hosts.back().m_rpcLogin = argv[++i];
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -172,6 +196,21 @@ Params::Params(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
auto invalid_host = [](const Host& h)
|
||||
{
|
||||
if (!h.valid()) {
|
||||
LOGERR(1, "Invalid host " << h.m_address << ':' << h.m_rpcPort << ":ZMQ:" << h.m_zmqPort << ". Try \"p2pool --help\".");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
m_hosts.erase(std::remove_if(m_hosts.begin(), m_hosts.end(), invalid_host), m_hosts.end());
|
||||
|
||||
if (m_hosts.empty()) {
|
||||
m_hosts.emplace_back(Host());
|
||||
}
|
||||
|
||||
if (m_stratumAddresses.empty()) {
|
||||
const int stratum_port = DEFAULT_STRATUM_PORT;
|
||||
|
||||
@@ -185,7 +224,44 @@ Params::Params(int argc, char* argv[])
|
||||
|
||||
bool Params::valid() const
|
||||
{
|
||||
return !m_host.empty() && m_rpcPort && m_zmqPort && m_wallet.valid();
|
||||
if (!m_wallet.valid()) {
|
||||
LOGERR(1, "Invalid wallet address. Try \"p2pool --help\".");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Params::Host::init_display_name(const Params& p)
|
||||
{
|
||||
m_displayName = m_address;
|
||||
|
||||
if (p.m_socks5Proxy.empty()) {
|
||||
if (p.m_dns) {
|
||||
bool is_v6;
|
||||
if (!resolve_host(m_address, is_v6)) {
|
||||
LOGERR(1, "resolve_host failed for " << m_address);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_address.find_first_not_of("0123456789.:") != std::string::npos) {
|
||||
LOGERR(1, "Can't resolve hostname " << m_address << " with DNS disabled");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1];
|
||||
buf[0] = '\0';
|
||||
log::Stream s(buf);
|
||||
|
||||
s << m_displayName << ':' << m_rpcPort << ":ZMQ:" << m_zmqPort;
|
||||
if (m_address != m_displayName) {
|
||||
s << " (" << m_address << ')';
|
||||
}
|
||||
|
||||
m_displayName.assign(buf, s.m_pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+27
-5
@@ -23,13 +23,36 @@ namespace p2pool {
|
||||
|
||||
struct Params
|
||||
{
|
||||
Params(int argc, char* argv[]);
|
||||
Params(int argc, char* const argv[]);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
std::string m_host = "127.0.0.1";
|
||||
uint32_t m_rpcPort = 18081;
|
||||
uint32_t m_zmqPort = 18083;
|
||||
struct Host
|
||||
{
|
||||
Host() : m_address("127.0.0.1"), m_rpcPort(18081), m_zmqPort(18083) {}
|
||||
|
||||
Host(const char* address, uint32_t rpcPort, uint32_t zmqPort, const char* rpcLogin)
|
||||
: m_address(address)
|
||||
, m_rpcPort(rpcPort)
|
||||
, m_zmqPort(zmqPort)
|
||||
, m_rpcLogin(rpcLogin)
|
||||
{}
|
||||
|
||||
bool valid() const { return !m_address.empty() && m_rpcPort && m_zmqPort && (m_rpcPort != m_zmqPort); }
|
||||
|
||||
bool init_display_name(const Params& p);
|
||||
|
||||
std::string m_address;
|
||||
uint32_t m_rpcPort;
|
||||
uint32_t m_zmqPort;
|
||||
|
||||
std::string m_rpcLogin;
|
||||
|
||||
std::string m_displayName;
|
||||
};
|
||||
|
||||
std::vector<Host> m_hosts;
|
||||
|
||||
bool m_lightMode = false;
|
||||
Wallet m_wallet{ nullptr };
|
||||
std::string m_stratumAddresses;
|
||||
@@ -49,7 +72,6 @@ struct Params
|
||||
uint32_t m_minerThreads = 0;
|
||||
bool m_mini = false;
|
||||
bool m_autoDiff = true;
|
||||
std::string m_rpcLogin;
|
||||
std::string m_socks5Proxy;
|
||||
bool m_dns = true;
|
||||
uint32_t m_p2pExternalPort = 0;
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "pow_hash.h"
|
||||
#include "crypto.h"
|
||||
|
||||
static constexpr char log_category_prefix[] = "PoolBlock ";
|
||||
LOG_CATEGORY(PoolBlock)
|
||||
|
||||
#include "pool_block_parser.inl"
|
||||
|
||||
|
||||
@@ -47,6 +47,12 @@ class SideChain;
|
||||
* Pool block's PoW hash is calculated from the Monero block template part using Monero's consensus rules
|
||||
*/
|
||||
|
||||
// 128 KB minus BLOCK_RESPONSE P2P protocol header (5 bytes)
|
||||
static constexpr uint64_t MAX_BLOCK_SIZE = 128 * 1024 - 5;
|
||||
|
||||
// 0.6 XMR
|
||||
static constexpr uint64_t BASE_BLOCK_REWARD = 600000000000ULL;
|
||||
|
||||
struct DifficultyData
|
||||
{
|
||||
FORCEINLINE DifficultyData(uint64_t t, const difficulty_type& d) : m_timestamp(t), m_cumulativeDifficulty(d) {}
|
||||
|
||||
@@ -27,7 +27,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
{
|
||||
try {
|
||||
// Sanity check
|
||||
if (!data || (size > 128 * 1024)) {
|
||||
if (!data || (size > MAX_BLOCK_SIZE)) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
READ_VARINT(tmp);
|
||||
|
||||
// Sanity check
|
||||
if ((tmp == 0) || (tmp > 128 * 1024)) {
|
||||
if ((tmp == 0) || (tmp > MAX_BLOCK_SIZE)) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
|
||||
// Technically some p2pool node could keep stuffing block with transactions until reward is less than 0.6 XMR
|
||||
// But default transaction picking algorithm never does that. It's better to just ban such nodes
|
||||
if (total_reward < 600000000000ULL) {
|
||||
if (total_reward < BASE_BLOCK_REWARD) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
@@ -341,6 +341,11 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
hash check;
|
||||
const std::vector<uint8_t>& consensus_id = sidechain.consensus_id();
|
||||
const int data_size = static_cast<int>((data_end - data_begin) + outputs_blob_size_diff + transactions_blob_size_diff);
|
||||
|
||||
if (data_size > static_cast<int>(MAX_BLOCK_SIZE)) {
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
keccak_custom(
|
||||
[nonce_offset, extra_nonce_offset, sidechain_hash_offset, data_begin, data_size, &consensus_id, &outputs_blob, outputs_blob_size_diff, outputs_offset, outputs_blob_size, transactions_blob, transactions_blob_size_diff, transactions_offset, transactions_blob_size](int offset) -> uint8_t
|
||||
{
|
||||
@@ -388,8 +393,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
const char* msg = e.what();
|
||||
LOGERR(0, "Exception in PoolBlock::deserialize(): " << (msg ? msg : "unknown exception"));
|
||||
LOGERR(0, "Exception in PoolBlock::deserialize(): " << e.what());
|
||||
return __LINE__;
|
||||
}
|
||||
|
||||
|
||||
+26
-15
@@ -29,7 +29,7 @@
|
||||
#include <rapidjson/document.h>
|
||||
#include <thread>
|
||||
|
||||
static constexpr char log_category_prefix[] = "RandomX_Hasher ";
|
||||
LOG_CATEGORY(RandomX_Hasher)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
@@ -322,6 +322,22 @@ void RandomX_Hasher::sync_wait()
|
||||
ReadLock lock2(m_cacheLock);
|
||||
}
|
||||
|
||||
static bool randomx_calculate_hash_safe(randomx_vm* machine, const void* input, size_t inputSize, void* output)
|
||||
{
|
||||
// Try to calculate the hash again if something went wrong the first time (for example, because of an unstable CPU)
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
try {
|
||||
randomx_calculate_hash(machine, input, inputSize, output);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(0, "Failed to calculate RandomX hash: exception \"" << e.what() << "\". Is your CPU/RAM unstable?" <<
|
||||
"\nFailed RandomX hash input: " << log::hex_buf(input, inputSize));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*/, const hash& seed, hash& result, bool force_light_mode)
|
||||
{
|
||||
// First try to use the dataset if it's ready
|
||||
@@ -335,8 +351,7 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*
|
||||
MutexLock lock(m_vm[FULL_DATASET_VM].mutex);
|
||||
|
||||
if (m_vm[FULL_DATASET_VM].vm && (seed == m_seed[m_index])) {
|
||||
randomx_calculate_hash(m_vm[FULL_DATASET_VM].vm, data, size, &result);
|
||||
return true;
|
||||
return randomx_calculate_hash_safe(m_vm[FULL_DATASET_VM].vm, data, size, &result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,8 +365,7 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*
|
||||
{
|
||||
MutexLock lock2(m_vm[m_index].mutex);
|
||||
if (m_vm[m_index].vm && (seed == m_seed[m_index])) {
|
||||
randomx_calculate_hash(m_vm[m_index].vm, data, size, &result);
|
||||
return true;
|
||||
return randomx_calculate_hash_safe(m_vm[m_index].vm, data, size, &result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,8 +374,7 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*
|
||||
MutexLock lock2(m_vm[prev_index].mutex);
|
||||
|
||||
if (m_vm[prev_index].vm && (seed == m_seed[prev_index])) {
|
||||
randomx_calculate_hash(m_vm[prev_index].vm, data, size, &result);
|
||||
return true;
|
||||
return randomx_calculate_hash_safe(m_vm[prev_index].vm, data, size, &result);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -383,7 +396,6 @@ RandomX_Hasher_RPC::RandomX_Hasher_RPC(p2pool* pool)
|
||||
GetLoopUserData(&m_loop);
|
||||
|
||||
uv_async_init_checked(&m_loop, &m_shutdownAsync, on_shutdown);
|
||||
uv_async_init_checked(&m_loop, &m_kickTheLoopAsync, nullptr);
|
||||
m_shutdownAsync.data = this;
|
||||
|
||||
uv_mutex_init_checked(&m_requestMutex);
|
||||
@@ -443,13 +455,14 @@ bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t h
|
||||
",\"block_blob\":\"" << log::hex_buf(data, size) << '"' <<
|
||||
",\"seed_hash\":\"\"}}\0";
|
||||
|
||||
volatile int result = 0;
|
||||
volatile bool done = false;
|
||||
std::atomic<int> result{ 0 };
|
||||
std::atomic<bool> done{ false };
|
||||
|
||||
const Params& params = m_pool->params();
|
||||
const Params::Host& host = m_pool->current_host();
|
||||
|
||||
JSONRPCRequest::call(params.m_host, params.m_rpcPort, buf, params.m_rpcLogin, params.m_socks5Proxy,
|
||||
[&result, &h](const char* data, size_t size)
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, buf, host.m_rpcLogin, params.m_socks5Proxy,
|
||||
[&result, &h](const char* data, size_t size, double)
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
if (doc.Parse(data, size).HasParseError() || !parseValue(doc, "result", h)) {
|
||||
@@ -459,7 +472,7 @@ bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t h
|
||||
}
|
||||
result = 1;
|
||||
},
|
||||
[this, &result, &done](const char* data, size_t size)
|
||||
[this, &result, &done](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGWARN(3, "RPC calc_pow: server returned error " << log::const_buf(data, size));
|
||||
@@ -471,8 +484,6 @@ bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t h
|
||||
uv_cond_signal(&m_cond);
|
||||
}, &m_loop);
|
||||
|
||||
uv_async_send(&m_kickTheLoopAsync);
|
||||
|
||||
{
|
||||
MutexLock lock2(m_condMutex);
|
||||
while (!done) {
|
||||
|
||||
@@ -115,13 +115,11 @@ private:
|
||||
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);
|
||||
|
||||
delete GetLoopUserData(&server->m_loop, false);
|
||||
}
|
||||
|
||||
+215
-76
@@ -40,7 +40,7 @@
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
static constexpr char log_category_prefix[] = "SideChain ";
|
||||
LOG_CATEGORY(SideChain)
|
||||
|
||||
static constexpr uint64_t MIN_DIFFICULTY = 100000;
|
||||
static constexpr size_t UNCLE_BLOCK_DEPTH = 3;
|
||||
@@ -66,6 +66,9 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
, m_chainWindowSize(2160)
|
||||
, m_unclePenalty(20)
|
||||
, m_precalcFinished(false)
|
||||
#ifdef DEV_TEST_SYNC
|
||||
, m_firstPruneTime(0)
|
||||
#endif
|
||||
{
|
||||
if (s_networkType == NetworkType::Invalid) {
|
||||
s_networkType = type;
|
||||
@@ -89,7 +92,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
|
||||
uv_rwlock_init_checked(&m_sidechainLock);
|
||||
uv_mutex_init_checked(&m_seenWalletsLock);
|
||||
uv_mutex_init_checked(&m_seenBlocksLock);
|
||||
uv_mutex_init_checked(&m_incomingBlocksLock);
|
||||
uv_rwlock_init_checked(&m_curDifficultyLock);
|
||||
|
||||
m_difficultyData.reserve(m_chainWindowSize);
|
||||
@@ -111,11 +114,11 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
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) {
|
||||
if ((s.m_pos == sizeof(default_config) - 1) && (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) {
|
||||
else if ((s.m_pos == sizeof(mini_config) - 1) && (memcmp(buf, mini_config, sizeof(mini_config) - 1) == 0)) {
|
||||
m_consensusId.assign(mini_consensus_id, mini_consensus_id + HASH_SIZE);
|
||||
}
|
||||
else {
|
||||
@@ -165,7 +168,8 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
|
||||
// Hide most consensus ID bytes, we only want it on screen to show that we're on the right sidechain
|
||||
memset(buf + 8, '*', HASH_SIZE * 2 - 16);
|
||||
m_consensusIdDisplayStr.assign(buf);
|
||||
m_consensusIdDisplayStr = buf;
|
||||
|
||||
LOGINFO(1, "consensus ID = " << log::LightCyan() << m_consensusIdDisplayStr.c_str());
|
||||
|
||||
memcpy(m_consensusHash.h, m_consensusId.data(), HASH_SIZE);
|
||||
@@ -197,6 +201,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||
}
|
||||
|
||||
m_uniquePrecalcInputs = new unordered_set<size_t>();
|
||||
m_uniquePrecalcInputs->reserve(1 << 18);
|
||||
}
|
||||
|
||||
SideChain::~SideChain()
|
||||
@@ -205,7 +210,7 @@ SideChain::~SideChain()
|
||||
|
||||
uv_rwlock_destroy(&m_sidechainLock);
|
||||
uv_mutex_destroy(&m_seenWalletsLock);
|
||||
uv_mutex_destroy(&m_seenBlocksLock);
|
||||
uv_mutex_destroy(&m_incomingBlocksLock);
|
||||
uv_rwlock_destroy(&m_curDifficultyLock);
|
||||
|
||||
for (const auto& it : m_blocksById) {
|
||||
@@ -451,7 +456,7 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
|
||||
hash h;
|
||||
keccak(tip->m_txkeySecSeed.h, HASH_SIZE, h.h);
|
||||
|
||||
uint64_t seed = *reinterpret_cast<uint64_t*>(h.h);
|
||||
uint64_t seed = *h.u64();
|
||||
if (seed == 0) seed = 1;
|
||||
|
||||
for (uint64_t i = 0, k; i < n - 1; ++i) {
|
||||
@@ -465,7 +470,7 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SideChain::block_seen(const PoolBlock& block)
|
||||
bool SideChain::incoming_block_seen(const PoolBlock& block)
|
||||
{
|
||||
// Check if it's some old block
|
||||
const PoolBlock* tip = m_chainTip;
|
||||
@@ -475,15 +480,35 @@ bool SideChain::block_seen(const PoolBlock& block)
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
|
||||
// Check if it was received before
|
||||
MutexLock lock(m_seenBlocksLock);
|
||||
return !m_seenBlocks.insert(block.get_full_id()).second;
|
||||
MutexLock lock(m_incomingBlocksLock);
|
||||
return !m_incomingBlocks.emplace(block.get_full_id(), cur_time).second;
|
||||
}
|
||||
|
||||
void SideChain::unsee_block(const PoolBlock& block)
|
||||
void SideChain::forget_incoming_block(const PoolBlock& block)
|
||||
{
|
||||
MutexLock lock(m_seenBlocksLock);
|
||||
m_seenBlocks.erase(block.get_full_id());
|
||||
MutexLock lock(m_incomingBlocksLock);
|
||||
m_incomingBlocks.erase(block.get_full_id());
|
||||
}
|
||||
|
||||
void SideChain::cleanup_incoming_blocks()
|
||||
{
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
|
||||
MutexLock lock(m_incomingBlocksLock);
|
||||
|
||||
// Forget seen blocks that were added more than 10 minutes ago
|
||||
hash h;
|
||||
for (auto i = m_incomingBlocks.begin(); i != m_incomingBlocks.end();) {
|
||||
if (cur_time < i->second + 10 * 60) {
|
||||
++i;
|
||||
}
|
||||
else {
|
||||
i = m_incomingBlocks.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_blocks)
|
||||
@@ -541,14 +566,14 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
hash seed;
|
||||
if (!m_pool->get_seed(block.m_txinGenHeight, seed)) {
|
||||
LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": couldn't get seed hash for mainchain height " << block.m_txinGenHeight);
|
||||
unsee_block(block);
|
||||
forget_incoming_block(block);
|
||||
return false;
|
||||
}
|
||||
|
||||
hash 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);
|
||||
forget_incoming_block(block);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -578,13 +603,21 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
", mainchain height = " << block.m_txinGenHeight
|
||||
);
|
||||
|
||||
bool not_enough_pow = true;
|
||||
|
||||
// Calculate the same hash second time to check if it's an unstable hardware that caused this
|
||||
hash pow_hash2;
|
||||
if (block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash2, true) && (pow_hash2 != pow_hash)) {
|
||||
LOGERR(0, "UNSTABLE HARDWARE DETECTED: Calculated the same hash twice, got different results: " << pow_hash << " != " << pow_hash2 << " (sidechain id = " << block.m_sidechainId << ')');
|
||||
if (block.m_difficulty.check_pow(pow_hash2)) {
|
||||
LOGINFO(3, "add_external_block second result has enough PoW for height = " << block.m_sidechainHeight << ", id = " << block.m_sidechainId);
|
||||
not_enough_pow = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (not_enough_pow) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool block_found = false;
|
||||
@@ -603,12 +636,15 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
}
|
||||
|
||||
if (block.m_sidechainId == m_watchBlockSidechainId) {
|
||||
LOGINFO(0, log::LightGreen() << "BLOCK FOUND: main chain block at height " << m_watchBlock.height << " was mined by this p2pool" << BLOCK_FOUND);
|
||||
const Wallet& w = m_pool->params().m_wallet;
|
||||
|
||||
const char* who = (block.m_minerWallet == w) ? "you" : "someone else in this p2pool";
|
||||
LOGINFO(0, log::LightGreen() << "BLOCK FOUND: main chain block at height " << m_watchBlock.height << " was mined by " << who << BLOCK_FOUND);
|
||||
|
||||
m_watchBlockSidechainId = {};
|
||||
data = m_watchBlock;
|
||||
block_found = true;
|
||||
|
||||
const Wallet& w = m_pool->params().m_wallet;
|
||||
const uint64_t payout = block.get_payout(w);
|
||||
if (payout) {
|
||||
LOGINFO(0, log::LightCyan() << "Your wallet " << log::LightGreen() << w << log::LightCyan() << " got a payout of " << log::LightGreen() << log::XMRAmount(payout) << log::LightCyan() << " in block " << log::LightGreen() << data.height);
|
||||
@@ -666,9 +702,6 @@ bool SideChain::add_block(const PoolBlock& block)
|
||||
|
||||
m_blocksByHeight[new_block->m_sidechainHeight].push_back(new_block);
|
||||
|
||||
// Pre-calculate eph_public_keys during initial sync
|
||||
launch_precalc(new_block);
|
||||
|
||||
update_depths(new_block);
|
||||
|
||||
if (new_block->m_verified) {
|
||||
@@ -707,7 +740,7 @@ void SideChain::watch_mainchain_block(const ChainMain& data, const hash& possibl
|
||||
m_watchBlockSidechainId = possible_id;
|
||||
}
|
||||
|
||||
bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
const PoolBlock* SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
{
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
@@ -719,7 +752,7 @@ bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
|
||||
// Don't return stale chain tip
|
||||
if (block && (block->m_txinGenHeight + 2 < m_pool->miner_data().height)) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -730,14 +763,14 @@ bool SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
}
|
||||
|
||||
if (!block) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
blob = block->serialize_mainchain_data();
|
||||
const std::vector<uint8_t> sidechain_data = block->serialize_sidechain_data();
|
||||
blob.insert(blob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
return true;
|
||||
return block;
|
||||
}
|
||||
|
||||
bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob, uv_loop_t* loop) const
|
||||
@@ -746,11 +779,12 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
|
||||
struct Data
|
||||
{
|
||||
FORCEINLINE Data() : counter(0) {}
|
||||
FORCEINLINE Data() : blockMinerWallet(nullptr), counter(0) {}
|
||||
Data(Data&&) = delete;
|
||||
Data& operator=(Data&&) = delete;
|
||||
|
||||
std::vector<MinerShare> tmpShares;
|
||||
Wallet blockMinerWallet;
|
||||
hash txkeySec;
|
||||
std::atomic<int> counter;
|
||||
};
|
||||
@@ -785,6 +819,7 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
}
|
||||
|
||||
data = std::make_shared<Data>();
|
||||
data->blockMinerWallet = block->m_minerWallet;
|
||||
data->txkeySec = block->m_txkeySec;
|
||||
|
||||
if (!get_shares(block, data->tmpShares) || !split_reward(total_reward, data->tmpShares, tmpRewards) || (tmpRewards.size() != data->tmpShares.size())) {
|
||||
@@ -798,6 +833,14 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
// Helper jobs call get_eph_public_key with indices in descending order
|
||||
// Current thread will process indices in ascending order so when they meet, everything will be cached
|
||||
if (loop) {
|
||||
// Avoid accessing block->m_minerWallet from other threads in "parallel_run" below
|
||||
for (MinerShare& share : data->tmpShares) {
|
||||
if (share.m_wallet == &block->m_minerWallet) {
|
||||
share.m_wallet = &data->blockMinerWallet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parallel_run(loop, [data]() {
|
||||
Data* d = data.get();
|
||||
hash eph_public_key;
|
||||
@@ -911,7 +954,7 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
|
||||
blocks_in_window.emplace(uncle_id);
|
||||
auto it = m_blocksById.find(uncle_id);
|
||||
if (it != m_blocksById.end()) {
|
||||
PoolBlock* uncle = it->second;
|
||||
const PoolBlock* uncle = it->second;
|
||||
if (tip_height - uncle->m_sidechainHeight < window_size) {
|
||||
++total_uncles_in_window;
|
||||
if (uncle->m_minerWallet == w) {
|
||||
@@ -987,7 +1030,7 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
|
||||
}
|
||||
|
||||
LOGINFO(0, "status" <<
|
||||
"\nMonero node = " << m_pool->host_str() <<
|
||||
"\nMonero node = " << m_pool->current_host().m_displayName <<
|
||||
"\nMain chain height = " << m_pool->block_template().height() <<
|
||||
"\nMain chain hashrate = " << log::Hashrate(network_hashrate) <<
|
||||
"\nSide chain ID = " << (is_default() ? "default" : (is_mini() ? "mini" : m_consensusIdDisplayStr.c_str())) <<
|
||||
@@ -1122,6 +1165,8 @@ uint64_t SideChain::bottom_height(const PoolBlock* tip) const
|
||||
uint64_t bottom_height;
|
||||
std::vector<MinerShare> shares;
|
||||
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
if (!get_shares(tip, shares, &bottom_height, true)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1259,6 +1304,30 @@ bool SideChain::get_difficulty(const PoolBlock* tip, std::vector<DifficultyData>
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SideChain::p2pool_update_available() const
|
||||
{
|
||||
constexpr uint32_t version = (P2POOL_VERSION_MAJOR << 16) | P2POOL_VERSION_MINOR;
|
||||
|
||||
difficulty_type total_p2pool_diff, newer_p2pool_diff;
|
||||
{
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
const PoolBlock* cur = m_chainTip;
|
||||
|
||||
for (uint64_t i = 0; (i < m_chainWindowSize) && cur; ++i, cur = get_parent(cur)) {
|
||||
if (cur->m_sidechainExtraBuf[0] == static_cast<uint32_t>(SoftwareID::P2Pool)) {
|
||||
total_p2pool_diff += cur->m_difficulty;
|
||||
if (cur->m_sidechainExtraBuf[1] > version) {
|
||||
newer_p2pool_diff += cur->m_difficulty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assume that a new version is out if >= 20% of hashrate is using it already
|
||||
return newer_p2pool_diff * 5 >= total_p2pool_diff;
|
||||
}
|
||||
|
||||
void SideChain::verify_loop(PoolBlock* block)
|
||||
{
|
||||
// PoW is already checked at this point
|
||||
@@ -1367,10 +1436,10 @@ void SideChain::verify(PoolBlock* block)
|
||||
// Deep block
|
||||
//
|
||||
// Blocks in PPLNS window (m_chainWindowSize) require up to m_chainWindowSize earlier blocks to verify
|
||||
// If a block is deeper than m_chainWindowSize * 2 - 1 it can't influence blocks in PPLNS window
|
||||
// If a block is deeper than (m_chainWindowSize - 1) * 2 + UNCLE_BLOCK_DEPTH it can't influence blocks in PPLNS window
|
||||
// Also, having so many blocks on top of this one means it was verified by the network at some point
|
||||
// We skip checks in this case to make pruning possible
|
||||
if (block->m_depth >= m_chainWindowSize * 2) {
|
||||
if (block->m_depth > (m_chainWindowSize - 1) * 2 + UNCLE_BLOCK_DEPTH) {
|
||||
LOGINFO(4, "block " << block->m_sidechainId << " skipped verification");
|
||||
block->m_verified = true;
|
||||
block->m_invalid = false;
|
||||
@@ -1499,7 +1568,7 @@ void SideChain::verify(PoolBlock* block)
|
||||
}
|
||||
|
||||
// Check that uncle and parent have the same ancestor (they must be on the same chain)
|
||||
PoolBlock* tmp = parent;
|
||||
const PoolBlock* tmp = parent;
|
||||
while (tmp->m_sidechainHeight > uncle->m_sidechainHeight) {
|
||||
tmp = get_parent(tmp);
|
||||
if (!tmp) {
|
||||
@@ -1522,7 +1591,7 @@ void SideChain::verify(PoolBlock* block)
|
||||
}
|
||||
|
||||
bool same_chain = false;
|
||||
PoolBlock* tmp2 = uncle;
|
||||
const PoolBlock* tmp2 = uncle;
|
||||
for (size_t j = 0; (j < UNCLE_BLOCK_DEPTH) && tmp && tmp2 && (tmp->m_sidechainHeight + UNCLE_BLOCK_DEPTH >= block->m_sidechainHeight); ++j) {
|
||||
if (tmp->m_parent == tmp2->m_parent) {
|
||||
same_chain = true;
|
||||
@@ -1719,6 +1788,7 @@ void SideChain::update_chain_tip(const PoolBlock* block)
|
||||
}
|
||||
}
|
||||
prune_old_blocks();
|
||||
cleanup_incoming_blocks();
|
||||
}
|
||||
}
|
||||
else if (block->m_sidechainHeight > tip->m_sidechainHeight) {
|
||||
@@ -1727,7 +1797,7 @@ void SideChain::update_chain_tip(const PoolBlock* block)
|
||||
" is not a longer chain than " << tip->m_sidechainId <<
|
||||
", height " << tip->m_sidechainHeight);
|
||||
}
|
||||
else if (block->m_sidechainHeight + UNCLE_BLOCK_DEPTH > tip->m_sidechainHeight) {
|
||||
else if (m_pool && (block->m_sidechainHeight + UNCLE_BLOCK_DEPTH > tip->m_sidechainHeight)) {
|
||||
LOGINFO(4, "possible uncle block: id = " << log::Gray() << block->m_sidechainId << log::NoColor() <<
|
||||
", height = " << log::Gray() << block->m_sidechainHeight);
|
||||
m_pool->update_block_template_async();
|
||||
@@ -1741,13 +1811,8 @@ void SideChain::update_chain_tip(const PoolBlock* block)
|
||||
|
||||
PoolBlock* SideChain::get_parent(const PoolBlock* block) const
|
||||
{
|
||||
if (block) {
|
||||
auto it = m_blocksById.find(block->m_parent);
|
||||
if (it != m_blocksById.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
auto it = m_blocksById.find(block->m_parent);
|
||||
return (it != m_blocksById.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candidate, bool& is_alternative) const
|
||||
@@ -1895,6 +1960,18 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida
|
||||
|
||||
void SideChain::update_depths(PoolBlock* block)
|
||||
{
|
||||
const uint64_t precalc_depth = m_chainWindowSize + UNCLE_BLOCK_DEPTH - 1;
|
||||
|
||||
auto update_depth = [this, precalc_depth](PoolBlock* b, const uint64_t new_depth) {
|
||||
const uint64_t old_depth = b->m_depth;
|
||||
if (old_depth < new_depth) {
|
||||
b->m_depth = new_depth;
|
||||
if ((old_depth < precalc_depth) && (new_depth >= precalc_depth)) {
|
||||
launch_precalc(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t i = 1; i <= UNCLE_BLOCK_DEPTH; ++i) {
|
||||
auto it = m_blocksByHeight.find(block->m_sidechainHeight + i);
|
||||
if (it == m_blocksByHeight.end()) {
|
||||
@@ -1907,12 +1984,12 @@ void SideChain::update_depths(PoolBlock* block)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
block->m_depth = std::max(block->m_depth, child->m_depth + 1);
|
||||
update_depth(block, child->m_depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find(child->m_uncles.begin(), child->m_uncles.end(), block->m_sidechainId) != child->m_uncles.end()) {
|
||||
block->m_depth = std::max(block->m_depth, child->m_depth + i);
|
||||
update_depth(block, child->m_depth + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1924,10 +2001,40 @@ void SideChain::update_depths(PoolBlock* block)
|
||||
blocks_to_update.pop_back();
|
||||
|
||||
// Verify this block and possibly other blocks on top of it when we're sure it will get verified
|
||||
if (!block->m_verified && ((block->m_depth >= m_chainWindowSize * 2) || (block->m_sidechainHeight == 0))) {
|
||||
if (!block->m_verified && ((block->m_depth > (m_chainWindowSize - 1) * 2 + UNCLE_BLOCK_DEPTH) || (block->m_sidechainHeight == 0))) {
|
||||
verify_loop(block);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i <= UNCLE_BLOCK_DEPTH; ++i) {
|
||||
auto it = m_blocksByHeight.find(block->m_sidechainHeight + i);
|
||||
if (it == m_blocksByHeight.end()) {
|
||||
continue;
|
||||
}
|
||||
for (PoolBlock* child : it->second) {
|
||||
const uint64_t old_depth = child->m_depth;
|
||||
|
||||
if (child->m_parent == block->m_sidechainId) {
|
||||
if (i != 1) {
|
||||
LOGWARN(3, "Block " << block->m_sidechainId << ": m_sidechainHeight is inconsistent with child's m_sidechainHeight.");
|
||||
return;
|
||||
}
|
||||
else if (block->m_depth > 0) {
|
||||
update_depth(child, block->m_depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (std::find(child->m_uncles.begin(), child->m_uncles.end(), block->m_sidechainId) != child->m_uncles.end()) {
|
||||
if (block->m_depth > i) {
|
||||
update_depth(child, block->m_depth - i);
|
||||
}
|
||||
}
|
||||
|
||||
if (child->m_depth > old_depth) {
|
||||
blocks_to_update.push_back(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto it = m_blocksById.find(block->m_parent);
|
||||
if (it != m_blocksById.end()) {
|
||||
if (it->second->m_sidechainHeight + 1 != block->m_sidechainHeight) {
|
||||
@@ -1936,7 +2043,7 @@ void SideChain::update_depths(PoolBlock* block)
|
||||
}
|
||||
|
||||
if (it->second->m_depth < block->m_depth + 1) {
|
||||
it->second->m_depth = block->m_depth + 1;
|
||||
update_depth(it->second, block->m_depth + 1);
|
||||
blocks_to_update.push_back(it->second);
|
||||
}
|
||||
}
|
||||
@@ -1954,7 +2061,7 @@ void SideChain::update_depths(PoolBlock* block)
|
||||
|
||||
const uint64_t d = block->m_sidechainHeight - it->second->m_sidechainHeight;
|
||||
if (it->second->m_depth < block->m_depth + d) {
|
||||
it->second->m_depth = block->m_depth + d;
|
||||
update_depth(it->second, block->m_depth + d);
|
||||
blocks_to_update.push_back(it->second);
|
||||
}
|
||||
}
|
||||
@@ -1978,22 +2085,20 @@ void SideChain::prune_old_blocks()
|
||||
|
||||
const uint64_t h = tip->m_sidechainHeight - prune_distance;
|
||||
|
||||
uint64_t num_blocks_pruned = 0;
|
||||
std::vector<PoolBlock*> blocks_to_prune;
|
||||
|
||||
for (auto it = m_blocksByHeight.begin(); (it != m_blocksByHeight.end()) && (it->first <= h);) {
|
||||
const uint64_t height = it->first;
|
||||
std::vector<PoolBlock*>& v = it->second;
|
||||
|
||||
v.erase(std::remove_if(v.begin(), v.end(),
|
||||
[this, prune_distance, cur_time, prune_delay, &num_blocks_pruned, height](PoolBlock* block)
|
||||
[this, prune_distance, cur_time, prune_delay, &blocks_to_prune, height](PoolBlock* block)
|
||||
{
|
||||
if ((block->m_depth >= prune_distance) || (cur_time >= block->m_localTimestamp + prune_delay)) {
|
||||
auto it2 = m_blocksById.find(block->m_sidechainId);
|
||||
if (it2 != m_blocksById.end()) {
|
||||
m_blocksById.erase(it2);
|
||||
unsee_block(*block);
|
||||
delete block;
|
||||
++num_blocks_pruned;
|
||||
blocks_to_prune.push_back(block);
|
||||
}
|
||||
else {
|
||||
LOGERR(1, "m_blocksByHeight and m_blocksById are inconsistent at height " << height << ". Fix the code!");
|
||||
@@ -2011,8 +2116,8 @@ void SideChain::prune_old_blocks()
|
||||
}
|
||||
}
|
||||
|
||||
if (num_blocks_pruned) {
|
||||
LOGINFO(4, "pruned " << num_blocks_pruned << " old blocks at heights <= " << h);
|
||||
if (!blocks_to_prune.empty()) {
|
||||
LOGINFO(4, "pruned " << blocks_to_prune.size() << " old blocks at heights <= " << h);
|
||||
|
||||
// If side-chain started pruning blocks it means the initial sync is complete
|
||||
// It's now safe to delete cached blocks
|
||||
@@ -2022,10 +2127,50 @@ void SideChain::prune_old_blocks()
|
||||
|
||||
// Pre-calc workers are not needed anymore
|
||||
finish_precalc();
|
||||
|
||||
// We can only delete old blocks after the precalc is stopped because it can still use some of them
|
||||
for (const PoolBlock* b : blocks_to_prune) {
|
||||
delete b;
|
||||
}
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
if (m_firstPruneTime == 0) {
|
||||
m_firstPruneTime = seconds_since_epoch();
|
||||
|
||||
// Test Monero node switching
|
||||
m_pool->reconnect_to_host();
|
||||
}
|
||||
|
||||
if ((cur_time >= m_firstPruneTime + 120) && !m_pool->stopped()) {
|
||||
LOGINFO(0, log::LightGreen() << "[DEV] Synchronization finished successfully, stopping P2Pool now");
|
||||
#ifdef DEV_TRACK_MEMORY
|
||||
show_top_10_allocations();
|
||||
#endif
|
||||
print_status(false);
|
||||
|
||||
StratumServer* server1 = m_pool->stratum_server();
|
||||
P2PServer* server2 = m_pool->p2p_server();
|
||||
|
||||
if (server1 && server2) {
|
||||
server1->print_status();
|
||||
server2->print_status();
|
||||
|
||||
server1->print_bans();
|
||||
server2->print_bans();
|
||||
|
||||
server1->show_workers_async();
|
||||
server2->show_peers_async();
|
||||
}
|
||||
|
||||
m_pool->print_hosts();
|
||||
bkg_jobs_tracker.print_status();
|
||||
m_pool->stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void SideChain::get_missing_blocks(std::vector<hash>& missing_blocks) const
|
||||
void SideChain::get_missing_blocks(unordered_set<hash>& missing_blocks) const
|
||||
{
|
||||
missing_blocks.clear();
|
||||
|
||||
@@ -2037,14 +2182,14 @@ void SideChain::get_missing_blocks(std::vector<hash>& missing_blocks) const
|
||||
}
|
||||
|
||||
if (!b.second->m_parent.empty() && (m_blocksById.find(b.second->m_parent) == m_blocksById.end())) {
|
||||
missing_blocks.push_back(b.second->m_parent);
|
||||
missing_blocks.insert(b.second->m_parent);
|
||||
}
|
||||
|
||||
int num_missing_uncles = 0;
|
||||
|
||||
for (const hash& h : b.second->m_uncles) {
|
||||
if (!h.empty() && (m_blocksById.find(h) == m_blocksById.end())) {
|
||||
missing_blocks.push_back(h);
|
||||
missing_blocks.insert(h);
|
||||
|
||||
// Get no more than 2 first missing uncles at a time from each block
|
||||
// Blocks with more than 2 uncles are very rare and they will be processed in several steps
|
||||
@@ -2156,7 +2301,7 @@ void SideChain::launch_precalc(const PoolBlock* block)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int h = UNCLE_BLOCK_DEPTH - 1; h >= 0; --h) {
|
||||
for (int h = UNCLE_BLOCK_DEPTH; h >= 0; --h) {
|
||||
auto it = m_blocksByHeight.find(block->m_sidechainHeight + m_chainWindowSize + h - 1);
|
||||
if (it == m_blocksByHeight.end()) {
|
||||
continue;
|
||||
@@ -2183,6 +2328,7 @@ void SideChain::precalc_worker()
|
||||
{
|
||||
do {
|
||||
PrecalcJob* job;
|
||||
size_t num_inputs;
|
||||
{
|
||||
MutexLock lock(m_precalcJobsMutex);
|
||||
|
||||
@@ -2205,22 +2351,29 @@ void SideChain::precalc_worker()
|
||||
uint8_t t[HASH_SIZE * 2 + sizeof(size_t)];
|
||||
memcpy(t, job->b->m_txkeySec.h, HASH_SIZE);
|
||||
|
||||
for (size_t i = 0, n = job->shares.size(); i < n; ++i) {
|
||||
const size_t n = job->shares.size();
|
||||
num_inputs = n;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
memcpy(t + HASH_SIZE, job->shares[i].m_wallet->view_public_key().h, HASH_SIZE);
|
||||
memcpy(t + HASH_SIZE * 2, &i, sizeof(i));
|
||||
if (!m_uniquePrecalcInputs->insert(robin_hood::hash_bytes(t, array_size(t))).second) {
|
||||
job->shares[i].m_wallet = nullptr;
|
||||
--num_inputs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0, n = job->shares.size(); i < n; ++i) {
|
||||
if (job->shares[i].m_wallet) {
|
||||
hash eph_public_key;
|
||||
uint8_t view_tag;
|
||||
job->shares[i].m_wallet->get_eph_public_key(job->b->m_txkeySec, i, eph_public_key, view_tag);
|
||||
if (num_inputs) {
|
||||
for (size_t i = 0, n = job->shares.size(); i < n; ++i) {
|
||||
if (job->shares[i].m_wallet) {
|
||||
hash eph_public_key;
|
||||
uint8_t view_tag;
|
||||
job->shares[i].m_wallet->get_eph_public_key(job->b->m_txkeySec, i, eph_public_key, view_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete job;
|
||||
} while (true);
|
||||
}
|
||||
@@ -2264,20 +2417,6 @@ void SideChain::finish_precalc()
|
||||
{
|
||||
LOGERR(1, "exception in finish_precalc(): " << e.what());
|
||||
}
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
if (m_pool) {
|
||||
LOGINFO(0, log::LightGreen() << "[DEV] Synchronization finished successfully, stopping P2Pool now");
|
||||
print_status(false);
|
||||
P2PServer* server = m_pool->p2p_server();
|
||||
if (server) {
|
||||
server->print_status();
|
||||
server->print_bans();
|
||||
server->show_peers_async();
|
||||
}
|
||||
m_pool->stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+16
-6
@@ -46,16 +46,18 @@ public:
|
||||
|
||||
void fill_sidechain_data(PoolBlock& block, std::vector<MinerShare>& shares) const;
|
||||
|
||||
bool block_seen(const PoolBlock& block);
|
||||
void unsee_block(const PoolBlock& block);
|
||||
bool incoming_block_seen(const PoolBlock& block);
|
||||
void forget_incoming_block(const PoolBlock& block);
|
||||
void cleanup_incoming_blocks();
|
||||
|
||||
bool add_external_block(PoolBlock& block, std::vector<hash>& missing_blocks);
|
||||
bool add_block(const PoolBlock& block);
|
||||
void get_missing_blocks(std::vector<hash>& missing_blocks) const;
|
||||
void get_missing_blocks(unordered_set<hash>& missing_blocks) const;
|
||||
|
||||
PoolBlock* find_block(const hash& id) const;
|
||||
void watch_mainchain_block(const ChainMain& data, const hash& possible_id);
|
||||
|
||||
bool get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
|
||||
const PoolBlock* get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
|
||||
bool get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob, uv_loop_t* loop) const;
|
||||
|
||||
void print_status(bool obtain_sidechain_lock = true) const;
|
||||
@@ -80,8 +82,11 @@ public:
|
||||
const PoolBlock* chainTip() const { return m_chainTip; }
|
||||
bool precalcFinished() const { return m_precalcFinished.load(); }
|
||||
|
||||
bool p2pool_update_available() const;
|
||||
|
||||
#ifdef P2POOL_UNIT_TESTS
|
||||
difficulty_type m_testMainChainDiff;
|
||||
const unordered_map<hash, PoolBlock*>& blocksById() const { return m_blocksById; }
|
||||
#endif
|
||||
|
||||
static bool split_reward(uint64_t reward, const std::vector<MinerShare>& shares, std::vector<uint64_t>& rewards);
|
||||
@@ -116,8 +121,9 @@ private:
|
||||
unordered_map<hash, uint64_t> m_seenWallets;
|
||||
uint64_t m_seenWalletsLastPruneTime;
|
||||
|
||||
uv_mutex_t m_seenBlocksLock;
|
||||
unordered_set<PoolBlock::full_id> m_seenBlocks;
|
||||
// Used to quickly cut off multiple broadcasts of the same block by different peers. Only the first broadcast will be processed.
|
||||
uv_mutex_t m_incomingBlocksLock;
|
||||
unordered_map<PoolBlock::full_id, uint64_t> m_incomingBlocks;
|
||||
|
||||
std::vector<DifficultyData> m_difficultyData;
|
||||
|
||||
@@ -152,6 +158,10 @@ private:
|
||||
|
||||
std::atomic<bool> m_precalcFinished;
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
uint64_t m_firstPruneTime;
|
||||
#endif
|
||||
|
||||
hash m_consensusHash;
|
||||
|
||||
void launch_precalc(const PoolBlock* block);
|
||||
|
||||
+124
-65
@@ -23,7 +23,7 @@
|
||||
#include "params.h"
|
||||
#include "p2pool_api.h"
|
||||
|
||||
static constexpr char log_category_prefix[] = "StratumServer ";
|
||||
LOG_CATEGORY(StratumServer)
|
||||
|
||||
static constexpr int DEFAULT_BACKLOG = 128;
|
||||
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
|
||||
@@ -37,12 +37,10 @@ static constexpr int32_t BAD_SHARE_POINTS = -5;
|
||||
static constexpr int32_t GOOD_SHARE_POINTS = 1;
|
||||
static constexpr int32_t BAN_THRESHOLD_POINTS = -15;
|
||||
|
||||
#include "tcp_server.inl"
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
StratumServer::StratumServer(p2pool* pool)
|
||||
: TCPServer(StratumClient::allocate)
|
||||
: TCPServer(DEFAULT_BACKLOG, StratumClient::allocate)
|
||||
, m_pool(pool)
|
||||
, m_autoDiff(pool->params().m_autoDiff)
|
||||
, m_rng(RandomDeviceSeed::instance)
|
||||
@@ -57,12 +55,15 @@ StratumServer::StratumServer(p2pool* pool)
|
||||
, m_totalFailedShares(0)
|
||||
, m_apiLastUpdateTime(0)
|
||||
{
|
||||
m_callbackBuf.resize(STRATUM_BUF_SIZE);
|
||||
|
||||
// Diffuse the initial state in case it has low quality
|
||||
m_rng.discard(10000);
|
||||
|
||||
m_hashrateData[0] = { seconds_since_epoch(), 0 };
|
||||
|
||||
uv_mutex_init_checked(&m_blobsQueueLock);
|
||||
uv_mutex_init_checked(&m_showWorkersLock);
|
||||
uv_mutex_init_checked(&m_rngLock);
|
||||
uv_rwlock_init_checked(&m_hashrateDataLock);
|
||||
|
||||
@@ -90,7 +91,16 @@ StratumServer::~StratumServer()
|
||||
{
|
||||
shutdown_tcp();
|
||||
|
||||
{
|
||||
MutexLock lock(m_blobsQueueLock);
|
||||
|
||||
for (BlobsData* data : m_blobsQueue) {
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
uv_mutex_destroy(&m_blobsQueueLock);
|
||||
uv_mutex_destroy(&m_showWorkersLock);
|
||||
uv_mutex_destroy(&m_rngLock);
|
||||
uv_rwlock_destroy(&m_hashrateDataLock);
|
||||
|
||||
@@ -107,6 +117,7 @@ void StratumServer::on_block(const BlockTemplate& block)
|
||||
const uint32_t num_connections = m_numConnections;
|
||||
if (num_connections == 0) {
|
||||
LOGINFO(4, "no clients connected");
|
||||
api_update_local_stats(seconds_since_epoch());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,32 +171,24 @@ void StratumServer::on_block(const BlockTemplate& block)
|
||||
|
||||
{
|
||||
MutexLock lock(m_blobsQueueLock);
|
||||
m_blobsQueue.push_back(blobs_data);
|
||||
}
|
||||
|
||||
if (uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_blobsAsync))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int err = uv_async_send(&m_blobsAsync);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_send failed, error " << uv_err_name(err));
|
||||
|
||||
bool found = false;
|
||||
{
|
||||
MutexLock lock(m_blobsQueueLock);
|
||||
|
||||
auto it = std::find(m_blobsQueue.begin(), m_blobsQueue.end(), blobs_data);
|
||||
if (it != m_blobsQueue.end()) {
|
||||
found = true;
|
||||
m_blobsQueue.erase(it);
|
||||
}
|
||||
if (uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_blobsAsync))) {
|
||||
delete blobs_data;
|
||||
return;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
m_blobsQueue.push_back(blobs_data);
|
||||
|
||||
const int err = uv_async_send(&m_blobsAsync);
|
||||
if (err) {
|
||||
LOGERR(1, "uv_async_send failed, error " << uv_err_name(err));
|
||||
|
||||
m_blobsQueue.pop_back();
|
||||
delete blobs_data;
|
||||
}
|
||||
}
|
||||
|
||||
api_update_local_stats(seconds_since_epoch());
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
@@ -202,8 +205,8 @@ static bool get_custom_user(const char* s, char (&user)[N])
|
||||
if ((c == '+') || (c == '.')) {
|
||||
break;
|
||||
}
|
||||
// Limit to printable ASCII characters
|
||||
if (c >= ' ' && c <= '~') {
|
||||
// Limit to printable ASCII characters, also skip comma and JSON special characters
|
||||
if (c >= ' ' && c <= '~' && c != ',' && c != '"' && c != '\\') {
|
||||
user[len++] = c;
|
||||
}
|
||||
++s;
|
||||
@@ -243,6 +246,11 @@ static bool get_custom_diff(const char* s, difficulty_type& diff)
|
||||
|
||||
bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* login)
|
||||
{
|
||||
if (client->m_rpcId) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " tried to login, but it's already logged in");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t extra_nonce = m_extraNonce.fetch_add(1);
|
||||
|
||||
uint8_t hashing_blob[128];
|
||||
@@ -284,13 +292,13 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
|
||||
client->m_lastJobTarget = target;
|
||||
|
||||
const bool result = send(client,
|
||||
[client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](void* buf, size_t buf_size)
|
||||
[client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
do {
|
||||
client->m_rpcId = static_cast<StratumServer*>(client->m_owner)->get_random32();
|
||||
} while (!client->m_rpcId);
|
||||
|
||||
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
|
||||
log::hex_buf target_hex(&target);
|
||||
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target_hex.m_data += sizeof(uint32_t);
|
||||
@@ -367,14 +375,14 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
}
|
||||
|
||||
if (found) {
|
||||
BlockTemplate& block = m_pool->block_template();
|
||||
const BlockTemplate& block = m_pool->block_template();
|
||||
uint64_t height, sidechain_height;
|
||||
difficulty_type mainchain_diff, sidechain_diff;
|
||||
|
||||
if (!block.get_difficulties(template_id, height, sidechain_height, mainchain_diff, sidechain_diff)) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share");
|
||||
return send(client,
|
||||
[id](void* buf, size_t buf_size)
|
||||
[id](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
log::Stream s(buf, buf_size);
|
||||
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n";
|
||||
@@ -407,7 +415,10 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
share->m_req.data = share;
|
||||
share->m_server = this;
|
||||
share->m_client = client;
|
||||
share->m_clientIPv6 = client->m_isV6;
|
||||
share->m_clientAddr = client->m_addr;
|
||||
memcpy(share->m_clientAddrString, client->m_addrString, sizeof(share->m_clientAddrString));
|
||||
memcpy(share->m_clientCustomUser, client->m_customUser, sizeof(share->m_clientCustomUser));
|
||||
share->m_clientResetCounter = client->m_resetCounter.load();
|
||||
share->m_rpcId = client->m_rpcId;
|
||||
share->m_id = id;
|
||||
@@ -459,7 +470,7 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a share with invalid job id " << job_id << " (latest job sent has id " << client->m_perConnectionJobId << ')');
|
||||
|
||||
const bool result = send(client,
|
||||
[id](void* buf, size_t buf_size)
|
||||
[id](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
log::Stream s(buf, buf_size);
|
||||
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Invalid job id\"}}\n";
|
||||
@@ -483,6 +494,8 @@ void StratumServer::print_status()
|
||||
|
||||
void StratumServer::show_workers_async()
|
||||
{
|
||||
MutexLock lock(m_showWorkersLock);
|
||||
|
||||
if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(&m_showWorkersAsync))) {
|
||||
uv_async_send(&m_showWorkersAsync);
|
||||
}
|
||||
@@ -540,6 +553,11 @@ void StratumServer::reset_share_counters()
|
||||
m_totalFailedShares = 0;
|
||||
}
|
||||
|
||||
const char* StratumServer::get_log_category() const
|
||||
{
|
||||
return log_category_prefix;
|
||||
}
|
||||
|
||||
void StratumServer::print_stratum_status() const
|
||||
{
|
||||
uint64_t hashes_15m, hashes_1h, hashes_24h, total_hashes;
|
||||
@@ -585,8 +603,8 @@ void StratumServer::print_stratum_status() const
|
||||
const uint64_t hashrate_24h = (dt_24h > 0) ? (hashes_24h / dt_24h) : 0;
|
||||
|
||||
char shares_failed_buf[64] = {};
|
||||
log::Stream s(shares_failed_buf);
|
||||
if (shares_failed) {
|
||||
log::Stream s(shares_failed_buf);
|
||||
s << log::Yellow() << "\nShares failed = " << shares_failed << log::NoColor();
|
||||
}
|
||||
|
||||
@@ -769,9 +787,9 @@ void StratumServer::on_blobs_ready()
|
||||
client->m_lastJobTarget = target;
|
||||
|
||||
const bool result = send(client,
|
||||
[data, target, hashing_blob, job_id](void* buf, size_t buf_size)
|
||||
[data, target, hashing_blob, job_id](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
|
||||
log::hex_buf target_hex(&target);
|
||||
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target_hex.m_data += sizeof(uint32_t);
|
||||
@@ -840,7 +858,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
|
||||
StratumServer* server = share->m_server;
|
||||
|
||||
if (server->is_banned(share->m_clientAddr)) {
|
||||
if (server->is_banned(share->m_clientIPv6, share->m_clientAddr)) {
|
||||
share->m_highEnoughDifficulty = false;
|
||||
share->m_result = SubmittedShare::Result::BANNED;
|
||||
return;
|
||||
@@ -850,7 +868,6 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
BACKGROUND_JOB_START(StratumServer::on_share_found);
|
||||
}
|
||||
|
||||
StratumClient* client = share->m_client;
|
||||
p2pool* pool = server->m_pool;
|
||||
|
||||
const uint64_t target = share->m_target;
|
||||
@@ -870,7 +887,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
|
||||
const uint32_t blob_size = pool->block_template().get_hashing_blob(share->m_templateId, share->m_extraNonce, blob, height, difficulty, sidechain_difficulty, seed_hash, nonce_offset);
|
||||
if (!blob_size) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share");
|
||||
LOGWARN(4, "client " << static_cast<char*>(share->m_clientAddrString) << " got a stale share");
|
||||
share->m_result = SubmittedShare::Result::STALE;
|
||||
return;
|
||||
}
|
||||
@@ -882,13 +899,13 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
|
||||
hash pow_hash;
|
||||
if (!pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash, false)) {
|
||||
LOGWARN(3, "client " << static_cast<char*>(client->m_addrString) << " couldn't check share PoW");
|
||||
LOGWARN(3, "client " << static_cast<char*>(share->m_clientAddrString) << " couldn't check share PoW");
|
||||
share->m_result = SubmittedShare::Result::COULDNT_CHECK_POW;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pow_hash != share->m_resultHash) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " submitted a share with invalid PoW");
|
||||
LOGWARN(4, "client " << static_cast<char*>(share->m_clientAddrString) << " submitted a share with invalid PoW");
|
||||
share->m_result = SubmittedShare::Result::INVALID_POW;
|
||||
share->m_score = BAD_SHARE_POINTS;
|
||||
|
||||
@@ -926,7 +943,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
}
|
||||
|
||||
// Send the response to miner
|
||||
const uint64_t value = *reinterpret_cast<uint64_t*>(share->m_resultHash.h + HASH_SIZE - sizeof(uint64_t));
|
||||
const uint64_t value = share->m_resultHash.u64()[HASH_SIZE / sizeof(uint64_t) - 1];
|
||||
|
||||
if (LIKELY(value < target)) {
|
||||
const uint64_t timestamp = share->m_timestamp;
|
||||
@@ -935,7 +952,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
share->m_result = SubmittedShare::Result::OK;
|
||||
}
|
||||
else {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a low diff share");
|
||||
LOGWARN(4, "client " << static_cast<char*>(share->m_clientAddrString) << " got a low diff share");
|
||||
share->m_result = SubmittedShare::Result::LOW_DIFF;
|
||||
share->m_score = BAD_SHARE_POINTS;
|
||||
}
|
||||
@@ -944,13 +961,11 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
{
|
||||
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
|
||||
StratumClient* client = share->m_client;
|
||||
client->m_score += share->m_score;
|
||||
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
const char* s = client->m_customUser;
|
||||
const char* s = share->m_clientCustomUser;
|
||||
if (share->m_result == SubmittedShare::Result::OK) {
|
||||
LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(client->m_addrString) << (*s ? ", user " : "") << s << ", effort " << share->m_effort << '%');
|
||||
LOGINFO(0, log::Green() << "SHARE FOUND: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(share->m_clientAddrString) << (*s ? ", user " : "") << s << ", effort " << share->m_effort << '%');
|
||||
}
|
||||
else {
|
||||
static const char* reason_list[] = {
|
||||
@@ -964,24 +979,26 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
|
||||
const size_t k = static_cast<size_t>(share->m_result);
|
||||
const char* reason = (k < array_size(reason_list)) ? reason_list[k] : "unknown";
|
||||
LOGWARN(0, log::Green() << "INVALID SHARE: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(client->m_addrString) << (*s ? ", user " : "") << s << ", reason: " << reason);
|
||||
LOGWARN(0, "INVALID SHARE: mainchain height " << share->m_mainchainHeight << ", sidechain height " << share->m_sidechainHeight << ", diff " << share->m_sidechainDifficulty << ", client " << static_cast<char*>(share->m_clientAddrString) << (*s ? ", user " : "") << s << ", reason: " << reason);
|
||||
}
|
||||
BACKGROUND_JOB_STOP(StratumServer::on_share_found);
|
||||
}
|
||||
|
||||
ON_SCOPE_LEAVE([share]()
|
||||
StratumServer* server = share->m_server;
|
||||
|
||||
ON_SCOPE_LEAVE([share, server]()
|
||||
{
|
||||
ASAN_POISON_MEMORY_REGION(share, sizeof(SubmittedShare));
|
||||
share->m_server->m_submittedSharesPool.push_back(share);
|
||||
server->m_submittedSharesPool.push_back(share);
|
||||
});
|
||||
|
||||
StratumServer* server = share->m_server;
|
||||
|
||||
const bool bad_share = (share->m_result == SubmittedShare::Result::LOW_DIFF) || (share->m_result == SubmittedShare::Result::INVALID_POW);
|
||||
|
||||
if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) {
|
||||
StratumClient* client = share->m_client;
|
||||
|
||||
if (client->m_resetCounter.load() == share->m_clientResetCounter) {
|
||||
const bool result = server->send(client,
|
||||
[share](void* buf, size_t buf_size)
|
||||
[share](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
log::Stream s(buf, buf_size);
|
||||
switch (share->m_result) {
|
||||
@@ -1007,6 +1024,8 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
return s.m_pos;
|
||||
});
|
||||
|
||||
client->m_score += share->m_score;
|
||||
|
||||
if (bad_share && (client->m_score <= BAN_THRESHOLD_POINTS)) {
|
||||
client->ban(DEFAULT_BAN_TIME);
|
||||
client->close();
|
||||
@@ -1016,18 +1035,25 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
}
|
||||
}
|
||||
else if (bad_share) {
|
||||
server->ban(share->m_clientAddr, DEFAULT_BAN_TIME);
|
||||
server->ban(share->m_clientIPv6, share->m_clientAddr, DEFAULT_BAN_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
void StratumServer::on_shutdown()
|
||||
{
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_blobsAsync), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_showWorkersAsync), nullptr);
|
||||
{
|
||||
MutexLock lock(m_blobsQueueLock);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_blobsAsync), nullptr);
|
||||
}
|
||||
{
|
||||
MutexLock lock(m_showWorkersLock);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_showWorkersAsync), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
StratumServer::StratumClient::StratumClient()
|
||||
: m_rpcId(0)
|
||||
: Client(m_stratumReadBuf, sizeof(m_stratumReadBuf))
|
||||
, m_rpcId(0)
|
||||
, m_perConnectionJobId(0)
|
||||
, m_connectedTime(0)
|
||||
, m_jobs{}
|
||||
@@ -1040,6 +1066,7 @@ StratumServer::StratumClient::StratumClient()
|
||||
, m_lastJobTarget(0)
|
||||
, m_score(0)
|
||||
{
|
||||
m_stratumReadBuf[0] = '\0';
|
||||
}
|
||||
|
||||
void StratumServer::StratumClient::reset()
|
||||
@@ -1072,7 +1099,7 @@ bool StratumServer::StratumClient::on_connect()
|
||||
|
||||
bool StratumServer::StratumClient::on_read(char* data, uint32_t size)
|
||||
{
|
||||
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + sizeof(m_readBuf))) {
|
||||
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + m_readBufSize)) {
|
||||
LOGERR(1, "client: invalid data pointer or size in on_read()");
|
||||
ban(DEFAULT_BAN_TIME);
|
||||
return false;
|
||||
@@ -1255,13 +1282,13 @@ bool StratumServer::StratumClient::process_submit(rapidjson::Document& doc, uint
|
||||
|
||||
void StratumServer::api_update_local_stats(uint64_t timestamp)
|
||||
{
|
||||
if (!m_pool->api() || !m_pool->params().m_localStats) {
|
||||
if (!m_pool->api() || !m_pool->params().m_localStats || m_pool->stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Rate limit to no more than once in 60 seconds.
|
||||
// Rate limit to no more than once in 20 seconds.
|
||||
uint64_t t = m_apiLastUpdateTime.load();
|
||||
if (timestamp < t + 60) {
|
||||
if (timestamp < t + 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1316,10 +1343,11 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
|
||||
uint32_t connections = m_numConnections;
|
||||
uint32_t incoming_connections = m_numIncomingConnections;
|
||||
|
||||
m_pool->api()->set(p2pool_api::Category::LOCAL, "stratum",
|
||||
[hashrate_15m, hashrate_1h, hashrate_24h, total_hashes, shares_found, shares_failed, average_effort, current_effort, connections, incoming_connections](log::Stream& s)
|
||||
{
|
||||
s << "{\"hashrate_15m\":" << hashrate_15m
|
||||
const double block_reward_share_percent = m_pool->side_chain().get_reward_share(m_pool->params().m_wallet) * 100.0;
|
||||
|
||||
CallOnLoop(&m_loop, [=]() {
|
||||
m_pool->api()->set(p2pool_api::Category::LOCAL, "stratum", [=](log::Stream& s) {
|
||||
s << "{\"hashrate_15m\":" << hashrate_15m
|
||||
<< ",\"hashrate_1h\":" << hashrate_1h
|
||||
<< ",\"hashrate_24h\":" << hashrate_24h
|
||||
<< ",\"total_hashes\":" << total_hashes
|
||||
@@ -1329,8 +1357,39 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
|
||||
<< ",\"current_effort\":" << current_effort
|
||||
<< ",\"connections\":" << connections
|
||||
<< ",\"incoming_connections\":" << incoming_connections
|
||||
<< "}";
|
||||
<< ",\"block_reward_share_percent\":" << block_reward_share_percent
|
||||
<< ",\"workers\":[";
|
||||
|
||||
const difficulty_type pool_diff = m_pool->side_chain().difficulty();
|
||||
bool first = true;
|
||||
|
||||
for (const StratumClient* client = static_cast<StratumClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<StratumClient*>(client->m_next)) {
|
||||
if (!first) {
|
||||
s << ',';
|
||||
}
|
||||
difficulty_type diff = pool_diff;
|
||||
if (client->m_lastJobTarget > 1) {
|
||||
uint64_t r;
|
||||
diff.lo = udiv128(1, 0, client->m_lastJobTarget, &r);
|
||||
diff.hi = 0;
|
||||
if (r) {
|
||||
++diff.lo;
|
||||
}
|
||||
}
|
||||
|
||||
s << '"' << static_cast<const char*>(client->m_addrString) << ','
|
||||
<< (timestamp - client->m_connectedTime) << ','
|
||||
<< diff << ','
|
||||
<< (client->m_autoDiff.lo / AUTO_DIFF_TARGET_TIME) << ','
|
||||
<< (client->m_rpcId ? client->m_customUser : "not logged in")
|
||||
<< '"';
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
s << "]}";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
+11
-2
@@ -28,7 +28,7 @@ class BlockTemplate;
|
||||
static constexpr size_t STRATUM_BUF_SIZE = log::Stream::BUF_SIZE + 1;
|
||||
static constexpr int DEFAULT_STRATUM_PORT = 3333;
|
||||
|
||||
class StratumServer : public TCPServer<STRATUM_BUF_SIZE, STRATUM_BUF_SIZE>
|
||||
class StratumServer : public TCPServer
|
||||
{
|
||||
public:
|
||||
explicit StratumServer(p2pool *pool);
|
||||
@@ -52,6 +52,8 @@ public:
|
||||
bool process_login(rapidjson::Document& doc, uint32_t id);
|
||||
bool process_submit(rapidjson::Document& doc, uint32_t id);
|
||||
|
||||
alignas(8) char m_stratumReadBuf[STRATUM_BUF_SIZE];
|
||||
|
||||
uint32_t m_rpcId;
|
||||
uint32_t m_perConnectionJobId;
|
||||
uint64_t m_connectedTime;
|
||||
@@ -59,6 +61,7 @@ public:
|
||||
enum {
|
||||
JOBS_SIZE = 4,
|
||||
AUTO_DIFF_SIZE = 64,
|
||||
CUSTOM_USER_SIZE = 32,
|
||||
};
|
||||
|
||||
struct SavedJob {
|
||||
@@ -78,7 +81,7 @@ public:
|
||||
|
||||
difficulty_type m_customDiff;
|
||||
difficulty_type m_autoDiff;
|
||||
char m_customUser[32];
|
||||
char m_customUser[CUSTOM_USER_SIZE];
|
||||
|
||||
uint64_t m_lastJobTarget;
|
||||
|
||||
@@ -95,6 +98,8 @@ public:
|
||||
void reset_share_counters();
|
||||
|
||||
private:
|
||||
const char* get_log_category() const override;
|
||||
|
||||
void print_stratum_status() const;
|
||||
void update_auto_diff(StratumClient* client, const uint64_t timestamp, const uint64_t hashes);
|
||||
|
||||
@@ -123,6 +128,7 @@ private:
|
||||
static void on_blobs_ready(uv_async_t* handle) { reinterpret_cast<StratumServer*>(handle->data)->on_blobs_ready(); }
|
||||
void on_blobs_ready();
|
||||
|
||||
uv_mutex_t m_showWorkersLock;
|
||||
uv_async_t m_showWorkersAsync;
|
||||
|
||||
static void on_show_workers(uv_async_t* handle) { reinterpret_cast<StratumServer*>(handle->data)->show_workers(); }
|
||||
@@ -138,7 +144,10 @@ private:
|
||||
uv_work_t m_req;
|
||||
StratumServer* m_server;
|
||||
StratumClient* m_client;
|
||||
bool m_clientIPv6;
|
||||
raw_ip m_clientAddr;
|
||||
char m_clientAddrString[Client::ADDR_STRING_SIZE];
|
||||
char m_clientCustomUser[StratumClient::CUSTOM_USER_SIZE];
|
||||
uint32_t m_clientResetCounter;
|
||||
uint32_t m_rpcId;
|
||||
uint32_t m_id;
|
||||
|
||||
@@ -15,16 +15,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include "common.h"
|
||||
#include "tcp_server.h"
|
||||
|
||||
static thread_local bool server_event_loop_thread = false;
|
||||
static thread_local void* server_event_loop_thread = nullptr;
|
||||
static thread_local const char* log_category_prefix = "TCPServer ";
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback allocate_new_client)
|
||||
TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_client)
|
||||
: m_allocateNewClient(allocate_new_client)
|
||||
, m_defaultBacklog(default_backlog)
|
||||
, m_loopThread{}
|
||||
, m_loopThreadCreated(false)
|
||||
#ifdef WITH_UPNP
|
||||
, m_portMapping(0)
|
||||
#endif
|
||||
@@ -71,9 +74,7 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
|
||||
m_connectedClientsList->m_prev = m_connectedClientsList;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
// cppcheck-suppress functionStatic
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::~TCPServer()
|
||||
TCPServer::~TCPServer()
|
||||
{
|
||||
if (m_finished.load() == 0) {
|
||||
LOGERR(1, "TCP wasn't shutdown properly");
|
||||
@@ -83,10 +84,7 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::~TCPServer()
|
||||
delete m_connectedClientsList;
|
||||
}
|
||||
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
template<typename T>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::parse_address_list(const std::string& address_list, T callback)
|
||||
void TCPServer::parse_address_list_internal(const std::string& address_list, Callback<void, bool, const std::string&, const std::string&, int>::Base&& callback)
|
||||
{
|
||||
if (address_list.empty()) {
|
||||
return;
|
||||
@@ -115,12 +113,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::parse_address_list(const std::str
|
||||
}
|
||||
}
|
||||
|
||||
const int port = atoi(address.substr(k2 + 1).c_str());
|
||||
const int port = strtol(address.substr(k2 + 1).c_str(), nullptr, 10);
|
||||
if ((port > 0) && (port < 65536)) {
|
||||
callback(is_v6, address, ip, port);
|
||||
}
|
||||
else {
|
||||
LOGWARN(1, "invalid IP:port " << address);
|
||||
error_invalid_ip(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +128,102 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::parse_address_list(const std::str
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string& listen_addresses, bool upnp)
|
||||
bool TCPServer::start_listening(bool is_v6, const std::string& ip, int port, std::string address)
|
||||
{
|
||||
if ((m_listenPort >= 0) && (m_listenPort != port)) {
|
||||
LOGERR(1, "all sockets must be listening on the same port number, fix the command line");
|
||||
return false;
|
||||
}
|
||||
|
||||
uv_tcp_t* socket = new uv_tcp_t();
|
||||
|
||||
int err = uv_tcp_init(&m_loop, socket);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create tcp server handle, error " << uv_err_name(err));
|
||||
delete socket;
|
||||
return false;
|
||||
}
|
||||
socket->data = this;
|
||||
|
||||
ON_SCOPE_LEAVE([is_v6, this, socket]()
|
||||
{
|
||||
const std::vector<uv_tcp_t*>& v = is_v6 ? m_listenSockets6 : m_listenSockets;
|
||||
if (std::find(v.begin(), v.end(), socket) == v.end()) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(socket), [](uv_handle_t* h) { delete reinterpret_cast<uv_tcp_t*>(h); });
|
||||
}
|
||||
});
|
||||
|
||||
err = uv_tcp_nodelay(socket, 1);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to set tcp_nodelay on tcp server handle, error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_v6) {
|
||||
if (address.empty()) {
|
||||
char buf[64] = {};
|
||||
log::Stream s(buf);
|
||||
s << '[' << ip << "]:" << port;
|
||||
address = buf;
|
||||
}
|
||||
|
||||
sockaddr_in6 addr6;
|
||||
err = uv_ip6_addr(ip.c_str(), port, &addr6);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to parse IPv6 address " << ip << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr6), UV_TCP_IPV6ONLY);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to bind tcp server IPv6 socket " << address << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (address.empty()) {
|
||||
char buf[64] = {};
|
||||
log::Stream s(buf);
|
||||
s << ip << ':' << port;
|
||||
address = buf;
|
||||
}
|
||||
|
||||
sockaddr_in addr;
|
||||
err = uv_ip4_addr(ip.c_str(), port, &addr);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to parse IPv4 address " << ip << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr), 0);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to bind tcp server IPv4 socket " << address << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
err = uv_listen(reinterpret_cast<uv_stream_t*>(socket), m_defaultBacklog, on_new_connection);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to listen on tcp server socket " << address << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_v6) {
|
||||
m_listenSockets6.push_back(socket);
|
||||
}
|
||||
else {
|
||||
m_listenSockets.push_back(socket);
|
||||
}
|
||||
|
||||
if (m_listenPort < 0) {
|
||||
m_listenPort = port;
|
||||
}
|
||||
|
||||
LOGINFO(1, "listening on " << log::Gray() << address);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPServer::start_listening(const std::string& listen_addresses, bool upnp)
|
||||
{
|
||||
if (listen_addresses.empty()) {
|
||||
LOGERR(1, "listen address not set");
|
||||
@@ -139,74 +231,11 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
|
||||
}
|
||||
|
||||
parse_address_list(listen_addresses,
|
||||
[this](bool is_v6, const std::string& address, const std::string& ip, int port)
|
||||
[this](bool is_v6, const std::string& /*address*/, const std::string& ip, int port)
|
||||
{
|
||||
if (m_listenPort < 0) {
|
||||
m_listenPort = port;
|
||||
}
|
||||
else if (m_listenPort != port) {
|
||||
LOGERR(1, "all sockets must be listening on the same port number, fix the command line");
|
||||
if (!start_listening(is_v6, ip, port)) {
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
uv_tcp_t* socket = new uv_tcp_t();
|
||||
|
||||
if (is_v6) {
|
||||
m_listenSockets6.push_back(socket);
|
||||
}
|
||||
else {
|
||||
m_listenSockets.push_back(socket);
|
||||
}
|
||||
|
||||
int err = uv_tcp_init(&m_loop, socket);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create tcp server handle, error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
socket->data = this;
|
||||
|
||||
err = uv_tcp_nodelay(socket, 1);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to set tcp_nodelay on tcp server handle, error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
if (is_v6) {
|
||||
sockaddr_in6 addr6;
|
||||
err = uv_ip6_addr(ip.c_str(), port, &addr6);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to parse IPv6 address " << ip << ", error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr6), UV_TCP_IPV6ONLY);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to bind tcp server IPv6 socket " << address << ", error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
}
|
||||
else {
|
||||
sockaddr_in addr;
|
||||
err = uv_ip4_addr(ip.c_str(), port, &addr);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to parse IPv4 address " << ip << ", error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr), 0);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to bind tcp server IPv4 socket " << address << ", error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
}
|
||||
|
||||
err = uv_listen(reinterpret_cast<uv_stream_t*>(socket), DEFAULT_BACKLOG, on_new_connection);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to listen on tcp server socket " << address << ", error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
LOGINFO(1, "listening on " << log::Gray() << address);
|
||||
});
|
||||
|
||||
#ifdef WITH_UPNP
|
||||
@@ -222,10 +251,11 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
|
||||
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
m_loopThreadCreated = true;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const char* ip, int port)
|
||||
bool TCPServer::connect_to_peer(bool is_v6, const char* ip, int port)
|
||||
{
|
||||
if (!ip || (strlen(ip) > sizeof(Client::m_addrString) - 16)) {
|
||||
LOGERR(1, "failed to parse IP address, too long");
|
||||
@@ -257,8 +287,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const
|
||||
return connect_to_peer(client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const raw_ip& ip, int port)
|
||||
bool TCPServer::connect_to_peer(bool is_v6, const raw_ip& ip, int port)
|
||||
{
|
||||
if (m_finished.load()) {
|
||||
return false;
|
||||
@@ -274,13 +303,17 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const
|
||||
return connect_to_peer(client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::is_banned(const raw_ip& ip)
|
||||
bool TCPServer::is_banned(bool is_v6, raw_ip ip)
|
||||
{
|
||||
if (ip.is_localhost()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's IPv6, check the whole /64 prefix
|
||||
if (is_v6 && !ip.is_ipv4_prefix()) {
|
||||
memset(ip.data + 8, 0, sizeof(ip.data) - 8);
|
||||
}
|
||||
|
||||
const auto cur_time = std::chrono::steady_clock::now();
|
||||
|
||||
MutexLock lock(m_bansLock);
|
||||
@@ -297,10 +330,9 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::is_banned(const raw_ip& ip)
|
||||
return false;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
bool TCPServer::connect_to_peer(Client* client)
|
||||
{
|
||||
if (is_banned(client->m_addr)) {
|
||||
if (is_banned(client->m_isV6, client->m_addr)) {
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " is banned, not connecting to it");
|
||||
return_client(client);
|
||||
return false;
|
||||
@@ -327,7 +359,11 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(sizeof(client->m_readBuf) >= sizeof(uv_connect_t), "READ_BUF_SIZE must be large enough");
|
||||
if (client->m_readBufSize < sizeof(uv_connect_t)) {
|
||||
LOGERR(1, "client read buf size is too small (" << client->m_readBufSize << " bytes), expected at least " << sizeof(uv_connect_t) << " bytes");
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&client->m_socket), on_connection_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
uv_connect_t* connect_request = reinterpret_cast<uv_connect_t*>(client->m_readBuf);
|
||||
memset(connect_request, 0, sizeof(uv_connect_t));
|
||||
@@ -345,7 +381,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
else {
|
||||
sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(&addr);
|
||||
addr4->sin_family = AF_INET;
|
||||
memcpy(&addr4->sin_addr, client->m_addr.data + 12, sizeof(in_addr));
|
||||
memcpy(&addr4->sin_addr, client->m_addr.data + sizeof(raw_ip::ipv4_prefix), sizeof(in_addr));
|
||||
addr4->sin_port = htons(static_cast<uint16_t>(client->m_port));
|
||||
}
|
||||
}
|
||||
@@ -359,7 +395,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
else {
|
||||
sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(&addr);
|
||||
addr4->sin_family = AF_INET;
|
||||
memcpy(&addr4->sin_addr, m_socks5ProxyIP.data + 12, sizeof(in_addr));
|
||||
memcpy(&addr4->sin_addr, m_socks5ProxyIP.data + sizeof(raw_ip::ipv4_prefix), sizeof(in_addr));
|
||||
addr4->sin_port = htons(static_cast<uint16_t>(m_socks5ProxyPort));
|
||||
}
|
||||
}
|
||||
@@ -379,17 +415,16 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
}
|
||||
|
||||
#ifdef P2POOL_DEBUGGING
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::check_event_loop_thread(const char* func)
|
||||
void TCPServer::check_event_loop_thread(const char* func) const
|
||||
{
|
||||
if (!server_event_loop_thread) {
|
||||
if (server_event_loop_thread != this) {
|
||||
LOGERR(1, func << " called from another thread, this is not thread safe");
|
||||
PANIC_STOP();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::close_sockets(bool listen_sockets)
|
||||
void TCPServer::close_sockets(bool listen_sockets)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
@@ -423,8 +458,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::close_sockets(bool listen_sockets
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::shutdown_tcp()
|
||||
void TCPServer::error_invalid_ip(const std::string& address)
|
||||
{
|
||||
LOGERR(1, "invalid IP:port " << address);
|
||||
}
|
||||
|
||||
void TCPServer::shutdown_tcp()
|
||||
{
|
||||
if (m_finished.exchange(1)) {
|
||||
return;
|
||||
@@ -438,36 +477,40 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::shutdown_tcp()
|
||||
}
|
||||
#endif
|
||||
|
||||
uv_thread_join(&m_loopThread);
|
||||
if (m_loopThreadCreated) {
|
||||
uv_thread_join(&m_loopThread);
|
||||
}
|
||||
|
||||
uv_mutex_destroy(&m_bansLock);
|
||||
|
||||
LOGINFO(1, "stopped");
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_status()
|
||||
void TCPServer::print_status()
|
||||
{
|
||||
LOGINFO(0, "status" <<
|
||||
"\nConnections = " << m_numConnections.load() << " (" << m_numIncomingConnections.load() << " incoming)"
|
||||
);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::ban(const raw_ip& ip, uint64_t seconds)
|
||||
void TCPServer::ban(bool is_v6, raw_ip ip, uint64_t seconds)
|
||||
{
|
||||
if (ip.is_localhost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's IPv6, ban the whole /64 prefix
|
||||
if (is_v6 && !ip.is_ipv4_prefix()) {
|
||||
memset(ip.data + 8, 0, sizeof(ip.data) - 8);
|
||||
}
|
||||
|
||||
const auto ban_time = std::chrono::steady_clock::now() + std::chrono::seconds(seconds);
|
||||
|
||||
MutexLock lock(m_bansLock);
|
||||
m_bans[ip] = ban_time;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_bans()
|
||||
void TCPServer::print_bans()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
const auto cur_time = steady_clock::now();
|
||||
@@ -482,8 +525,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_bans()
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, SendCallbackBase&& callback)
|
||||
bool TCPServer::send_internal(Client* client, Callback<size_t, uint8_t*, size_t>::Base&& callback)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
@@ -492,23 +534,20 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
|
||||
return true;
|
||||
}
|
||||
|
||||
WriteBuf* buf = get_write_buffer();
|
||||
const size_t bytes_written = callback(m_callbackBuf.data(), m_callbackBuf.size());
|
||||
|
||||
// callback_buf is used in only 1 thread, so it's safe
|
||||
static uint8_t callback_buf[WRITE_BUF_SIZE];
|
||||
const size_t bytes_written = callback(callback_buf, sizeof(callback_buf));
|
||||
|
||||
if (bytes_written > WRITE_BUF_SIZE) {
|
||||
LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes");
|
||||
if (bytes_written > m_callbackBuf.size()) {
|
||||
LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << m_callbackBuf.size() << " bytes");
|
||||
PANIC_STOP();
|
||||
}
|
||||
|
||||
if (bytes_written == 0) {
|
||||
LOGWARN(1, "send callback wrote 0 bytes, nothing to do");
|
||||
return_write_buffer(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
WriteBuf* buf = get_write_buffer(bytes_written);
|
||||
|
||||
buf->m_write.data = buf;
|
||||
buf->m_client = client;
|
||||
|
||||
@@ -521,7 +560,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(buf->m_data, callback_buf, bytes_written);
|
||||
memcpy(buf->m_data, m_callbackBuf.data(), bytes_written);
|
||||
|
||||
uv_buf_t bufs[1];
|
||||
bufs[0].base = reinterpret_cast<char*>(buf->m_data);
|
||||
@@ -537,21 +576,31 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
const char* TCPServer::get_log_category() const
|
||||
{
|
||||
return log_category_prefix;
|
||||
}
|
||||
|
||||
void TCPServer::loop(void* data)
|
||||
{
|
||||
LOGINFO(1, "event loop started");
|
||||
server_event_loop_thread = true;
|
||||
TCPServer* server = static_cast<TCPServer*>(data);
|
||||
|
||||
server->m_writeBuffers.resize(DEFAULT_BACKLOG);
|
||||
server->m_preallocatedClients.reserve(DEFAULT_BACKLOG);
|
||||
for (size_t i = 0; i < DEFAULT_BACKLOG; ++i) {
|
||||
log_category_prefix = server->get_log_category();
|
||||
|
||||
LOGINFO(1, "event loop started");
|
||||
server_event_loop_thread = data;
|
||||
|
||||
server->m_preallocatedClients.reserve(server->m_defaultBacklog);
|
||||
for (int i = 0; i < server->m_defaultBacklog; ++i) {
|
||||
WriteBuf* wb = new WriteBuf();
|
||||
const size_t capacity = wb->m_dataCapacity;
|
||||
|
||||
Client* c = server->m_allocateNewClient();
|
||||
|
||||
ASAN_POISON_MEMORY_REGION(wb, sizeof(WriteBuf));
|
||||
ASAN_POISON_MEMORY_REGION(c, c->size());
|
||||
server->m_writeBuffers[i] = wb;
|
||||
c->asan_poison_this();
|
||||
|
||||
server->m_writeBuffers.emplace(capacity, wb);
|
||||
server->m_preallocatedClients.emplace_back(c);
|
||||
}
|
||||
|
||||
@@ -565,7 +614,9 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
LOGWARN(1, "uv_loop_close returned error " << uv_err_name(err));
|
||||
}
|
||||
|
||||
for (WriteBuf* buf : server->m_writeBuffers) {
|
||||
for (const auto& it : server->m_writeBuffers) {
|
||||
WriteBuf* buf = it.second;
|
||||
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
if (buf->m_data) {
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf->m_data, buf->m_dataCapacity);
|
||||
@@ -585,8 +636,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
LOGINFO(1, "event loop stopped");
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_connection(uv_stream_t* server, int status)
|
||||
void TCPServer::on_new_connection(uv_stream_t* server, int status)
|
||||
{
|
||||
TCPServer* pThis = static_cast<TCPServer*>(server->data);
|
||||
|
||||
@@ -602,17 +652,16 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_connection(uv_stream_t* se
|
||||
pThis->on_new_client(server);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_close(uv_handle_t* handle)
|
||||
void TCPServer::on_connection_close(uv_handle_t* handle)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
Client* client = static_cast<Client*>(handle->data);
|
||||
TCPServer* owner = client->m_owner;
|
||||
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " disconnected");
|
||||
|
||||
if (owner) {
|
||||
owner->check_event_loop_thread(__func__);
|
||||
|
||||
Client* prev_in_list = client->m_prev;
|
||||
Client* next_in_list = client->m_next;
|
||||
|
||||
@@ -635,15 +684,13 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_close(uv_handle_t*
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_error(uv_handle_t* handle)
|
||||
void TCPServer::on_connection_error(uv_handle_t* handle)
|
||||
{
|
||||
Client* client = reinterpret_cast<Client*>(handle->data);
|
||||
client->m_owner->return_client(client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connect(uv_connect_t* req, int status)
|
||||
void TCPServer::on_connect(uv_connect_t* req, int status)
|
||||
{
|
||||
Client* client = reinterpret_cast<Client*>(req->data);
|
||||
|
||||
@@ -669,8 +716,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connect(uv_connect_t* req, int
|
||||
server->on_new_client(nullptr, client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server)
|
||||
void TCPServer::on_new_client(uv_stream_t* server)
|
||||
{
|
||||
if (m_finished.load()) {
|
||||
return;
|
||||
@@ -704,8 +750,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
on_new_client(server, client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server, Client* client)
|
||||
void TCPServer::on_new_client(uv_stream_t* server, Client* client)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
@@ -737,10 +782,8 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
client->m_port = ntohs(reinterpret_cast<sockaddr_in6*>(&peer_addr)->sin6_port);
|
||||
}
|
||||
else {
|
||||
client->m_addr = {};
|
||||
client->m_addr.data[10] = 0xFF;
|
||||
client->m_addr.data[11] = 0xFF;
|
||||
memcpy(client->m_addr.data + 12, &reinterpret_cast<sockaddr_in*>(&peer_addr)->sin_addr, sizeof(in_addr));
|
||||
memcpy(client->m_addr.data, raw_ip::ipv4_prefix, sizeof(raw_ip::ipv4_prefix));
|
||||
memcpy(client->m_addr.data + sizeof(raw_ip::ipv4_prefix), &reinterpret_cast<sockaddr_in*>(&peer_addr)->sin_addr, sizeof(in_addr));
|
||||
client->m_port = ntohs(reinterpret_cast<sockaddr_in*>(&peer_addr)->sin_port);
|
||||
}
|
||||
|
||||
@@ -749,7 +792,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
|
||||
LOGINFO(5, "new connection " << (client->m_isIncoming ? "from " : "to ") << log::Gray() << static_cast<char*>(client->m_addrString));
|
||||
|
||||
if (is_banned(client->m_addr)) {
|
||||
if (is_banned(client->m_isV6, client->m_addr)) {
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " is banned, disconnecting");
|
||||
client->close();
|
||||
return;
|
||||
@@ -770,16 +813,15 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
}
|
||||
else {
|
||||
const bool result = owner->send(client,
|
||||
[](void* buf, size_t buf_size) -> size_t
|
||||
[](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
if (buf_size < 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
|
||||
p[0] = 5; // Protocol version (SOCKS5)
|
||||
p[1] = 1; // NMETHODS
|
||||
p[2] = 0; // Method 0 (no authentication)
|
||||
buf[0] = 5; // Protocol version (SOCKS5)
|
||||
buf[1] = 1; // NMETHODS
|
||||
buf[2] = 0; // Method 0 (no authentication)
|
||||
|
||||
return 3;
|
||||
});
|
||||
@@ -799,8 +841,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_shutdown(uv_async_t* async)
|
||||
void TCPServer::on_shutdown(uv_async_t* async)
|
||||
{
|
||||
TCPServer* s = reinterpret_cast<TCPServer*>(async->data);
|
||||
s->on_shutdown();
|
||||
@@ -819,7 +860,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_shutdown(uv_async_t* async)
|
||||
|
||||
uv_timer_init(&s->m_loop, &s->m_shutdownTimer);
|
||||
s->m_shutdownTimer.data = s;
|
||||
|
||||
#ifdef DEV_TEST_SYNC
|
||||
s->m_shutdownCountdown = 300;
|
||||
#else
|
||||
s->m_shutdownCountdown = 30;
|
||||
#endif
|
||||
|
||||
uv_timer_start(&s->m_shutdownTimer,
|
||||
[](uv_timer_t* h)
|
||||
@@ -860,14 +906,20 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_shutdown(uv_async_t* async)
|
||||
});
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::WriteBuf* TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::get_write_buffer()
|
||||
TCPServer::WriteBuf* TCPServer::get_write_buffer(size_t size_hint)
|
||||
{
|
||||
WriteBuf* buf;
|
||||
|
||||
if (!m_writeBuffers.empty()) {
|
||||
buf = m_writeBuffers.back();
|
||||
m_writeBuffers.pop_back();
|
||||
// Try to find the smallest buffer that still has enough capacity
|
||||
// If there is no buffer with enough capacity, just take the largest available buffer
|
||||
auto it = m_writeBuffers.lower_bound(size_hint);
|
||||
if (it == m_writeBuffers.end()) {
|
||||
it = std::prev(it);
|
||||
}
|
||||
|
||||
buf = it->second;
|
||||
m_writeBuffers.erase(it);
|
||||
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
if (buf->m_data) {
|
||||
@@ -881,19 +933,19 @@ typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::WriteBuf* TCPServer<READ_BUF_
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::return_write_buffer(WriteBuf* buf)
|
||||
void TCPServer::return_write_buffer(WriteBuf* buf)
|
||||
{
|
||||
const size_t capacity = buf->m_dataCapacity;
|
||||
|
||||
if (buf->m_data) {
|
||||
ASAN_POISON_MEMORY_REGION(buf->m_data, buf->m_dataCapacity);
|
||||
ASAN_POISON_MEMORY_REGION(buf->m_data, capacity);
|
||||
}
|
||||
ASAN_POISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
|
||||
m_writeBuffers.push_back(buf);
|
||||
m_writeBuffers.emplace(capacity, buf);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client* TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::get_client()
|
||||
TCPServer::Client* TCPServer::get_client()
|
||||
{
|
||||
Client* c;
|
||||
|
||||
@@ -911,16 +963,16 @@ typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client* TCPServer<READ_BUF_SI
|
||||
return c;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::return_client(Client* c)
|
||||
void TCPServer::return_client(Client* c)
|
||||
{
|
||||
ASAN_POISON_MEMORY_REGION(c, c->size());
|
||||
c->asan_poison_this();
|
||||
m_preallocatedClients.push_back(c);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client()
|
||||
: m_owner(nullptr)
|
||||
TCPServer::Client::Client(char* read_buf, size_t size)
|
||||
: m_readBuf(read_buf)
|
||||
, m_readBufSize(static_cast<uint32_t>(size))
|
||||
, m_owner(nullptr)
|
||||
, m_prev(nullptr)
|
||||
, m_next(nullptr)
|
||||
, m_socket{}
|
||||
@@ -936,11 +988,10 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client()
|
||||
, m_resetCounter{ 0 }
|
||||
{
|
||||
m_readBuf[0] = '\0';
|
||||
m_readBuf[READ_BUF_SIZE - 1] = '\0';
|
||||
m_readBuf[m_readBufSize - 1] = '\0';
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::reset()
|
||||
void TCPServer::Client::reset()
|
||||
{
|
||||
m_resetCounter.fetch_add(1);
|
||||
|
||||
@@ -958,11 +1009,10 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::reset()
|
||||
m_addrString[0] = '\0';
|
||||
m_socks5ProxyState = Socks5ProxyState::Default;
|
||||
m_readBuf[0] = '\0';
|
||||
m_readBuf[READ_BUF_SIZE - 1] = '\0';
|
||||
m_readBuf[m_readBufSize - 1] = '\0';
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_alloc(uv_handle_t* handle, size_t /*suggested_size*/, uv_buf_t* buf)
|
||||
void TCPServer::Client::on_alloc(uv_handle_t* handle, size_t /*suggested_size*/, uv_buf_t* buf)
|
||||
{
|
||||
Client* pThis = static_cast<Client*>(handle->data);
|
||||
|
||||
@@ -973,20 +1023,19 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_alloc(uv_handle_t* han
|
||||
return;
|
||||
}
|
||||
|
||||
if (pThis->m_numRead >= sizeof(pThis->m_readBuf)) {
|
||||
if (pThis->m_numRead >= pThis->m_readBufSize) {
|
||||
LOGWARN(4, "client " << static_cast<const char*>(pThis->m_addrString) << " read buffer is full");
|
||||
buf->len = 0;
|
||||
buf->base = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
buf->len = sizeof(pThis->m_readBuf) - pThis->m_numRead;
|
||||
buf->len = pThis->m_readBufSize - pThis->m_numRead;
|
||||
buf->base = pThis->m_readBuf + pThis->m_numRead;
|
||||
pThis->m_readBufInUse = true;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
void TCPServer::Client::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
Client* client = static_cast<Client*>(stream->data);
|
||||
client->m_readBufInUse = false;
|
||||
@@ -1021,10 +1070,9 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_read(uv_stream_t* stre
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_proxy_handshake(char* data, uint32_t size)
|
||||
bool TCPServer::Client::on_proxy_handshake(char* data, uint32_t size)
|
||||
{
|
||||
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + sizeof(m_readBuf))) {
|
||||
if ((data != m_readBuf + m_numRead) || (data + size > m_readBuf + m_readBufSize)) {
|
||||
LOGERR(1, "peer " << static_cast<char*>(m_addrString) << " invalid data pointer or size in on_read()");
|
||||
return false;
|
||||
}
|
||||
@@ -1042,27 +1090,26 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_proxy_handshake(char*
|
||||
n = 2;
|
||||
|
||||
const bool result = m_owner->send(this,
|
||||
[this](void* buf, size_t buf_size) -> size_t
|
||||
[this](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
if (buf_size < 22) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
|
||||
p[0] = 5; // Protocol version (SOCKS5)
|
||||
p[1] = 1; // CONNECT
|
||||
p[2] = 0; // RESERVED
|
||||
buf[0] = 5; // Protocol version (SOCKS5)
|
||||
buf[1] = 1; // CONNECT
|
||||
buf[2] = 0; // RESERVED
|
||||
if (m_isV6) {
|
||||
p[3] = 4; // ATYP
|
||||
memcpy(p + 4, m_addr.data, 16);
|
||||
p[20] = static_cast<uint8_t>(m_port >> 8);
|
||||
p[21] = static_cast<uint8_t>(m_port & 0xFF);
|
||||
buf[3] = 4; // ATYP
|
||||
memcpy(buf + 4, m_addr.data, 16);
|
||||
buf[20] = static_cast<uint8_t>(m_port >> 8);
|
||||
buf[21] = static_cast<uint8_t>(m_port & 0xFF);
|
||||
}
|
||||
else {
|
||||
p[3] = 1; // ATYP
|
||||
memcpy(p + 4, m_addr.data + 12, 4);
|
||||
p[8] = static_cast<uint8_t>(m_port >> 8);
|
||||
p[9] = static_cast<uint8_t>(m_port & 0xFF);
|
||||
buf[3] = 1; // ATYP
|
||||
memcpy(buf + 4, m_addr.data + sizeof(raw_ip::ipv4_prefix), 4);
|
||||
buf[8] = static_cast<uint8_t>(m_port >> 8);
|
||||
buf[9] = static_cast<uint8_t>(m_port & 0xFF);
|
||||
}
|
||||
|
||||
return m_isV6 ? 22 : 10;
|
||||
@@ -1079,7 +1126,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_proxy_handshake(char*
|
||||
|
||||
case Socks5ProxyState::ConnectRequestSent:
|
||||
if (m_numRead >= 4) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(m_readBuf);
|
||||
const uint8_t* p = reinterpret_cast<uint8_t*>(m_readBuf);
|
||||
if ((p[0] != 5) && (p[1] != 0) && p[2] != 0) {
|
||||
LOGWARN(5, "SOCKS5 proxy returned an invalid reply to CONNECT");
|
||||
return false;
|
||||
@@ -1143,8 +1190,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_proxy_handshake(char*
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_write(uv_write_t* req, int status)
|
||||
void TCPServer::Client::on_write(uv_write_t* req, int status)
|
||||
{
|
||||
WriteBuf* buf = static_cast<WriteBuf*>(req->data);
|
||||
Client* client = buf->m_client;
|
||||
@@ -1160,16 +1206,16 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_write(uv_write_t* req,
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::close()
|
||||
void TCPServer::Client::close()
|
||||
{
|
||||
if (m_isClosing || !m_owner) {
|
||||
// Already closed
|
||||
return;
|
||||
}
|
||||
|
||||
m_isClosing = true;
|
||||
|
||||
m_owner->check_event_loop_thread(__func__);
|
||||
|
||||
uv_read_stop(reinterpret_cast<uv_stream_t*>(&m_socket));
|
||||
|
||||
uv_tcp_t* s = &m_socket;
|
||||
@@ -1179,8 +1225,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::close()
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::ban(uint64_t seconds)
|
||||
void TCPServer::Client::ban(uint64_t seconds)
|
||||
{
|
||||
if (m_addr.is_localhost()) {
|
||||
return;
|
||||
@@ -1188,12 +1233,11 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::ban(uint64_t seconds)
|
||||
|
||||
if (m_owner) {
|
||||
LOGWARN(3, "peer " << static_cast<char*>(m_addrString) << " banned for " << seconds << " seconds");
|
||||
m_owner->ban(m_addr, seconds);
|
||||
m_owner->ban(m_isV6, m_addr, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::init_addr_string()
|
||||
void TCPServer::Client::init_addr_string()
|
||||
{
|
||||
const char* addr_str;
|
||||
char addr_str_buf[64];
|
||||
@@ -1202,7 +1246,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::init_addr_string()
|
||||
addr_str = inet_ntop(AF_INET6, m_addr.data, addr_str_buf, sizeof(addr_str_buf));
|
||||
}
|
||||
else {
|
||||
addr_str = inet_ntop(AF_INET, m_addr.data + 12, addr_str_buf, sizeof(addr_str_buf));
|
||||
addr_str = inet_ntop(AF_INET, m_addr.data + sizeof(raw_ip::ipv4_prefix), addr_str_buf, sizeof(addr_str_buf));
|
||||
}
|
||||
|
||||
if (addr_str) {
|
||||
@@ -1221,4 +1265,17 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::init_addr_string()
|
||||
}
|
||||
}
|
||||
|
||||
void TCPServer::Client::asan_poison_this() const
|
||||
{
|
||||
#ifdef P2POOL_ASAN
|
||||
const uint8_t* begin = reinterpret_cast<const uint8_t*>(this);
|
||||
const uint8_t* counter_begin = reinterpret_cast<const uint8_t*>(&m_resetCounter);
|
||||
const uint8_t* counter_end = counter_begin + sizeof(m_resetCounter);
|
||||
const uint8_t* end = begin + size();
|
||||
|
||||
ASAN_POISON_MEMORY_REGION(begin, counter_begin - begin);
|
||||
ASAN_POISON_MEMORY_REGION(counter_end, end - counter_end);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace p2pool
|
||||
+36
-33
@@ -18,22 +18,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "uv_util.h"
|
||||
#include <map>
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
class TCPServer : public nocopy_nomove
|
||||
{
|
||||
public:
|
||||
struct Client;
|
||||
typedef Client* (*allocate_client_callback)();
|
||||
|
||||
explicit TCPServer(allocate_client_callback allocate_new_client);
|
||||
TCPServer(int default_backlog, allocate_client_callback allocate_new_client);
|
||||
virtual ~TCPServer();
|
||||
|
||||
template<typename T>
|
||||
void parse_address_list(const std::string& address_list, T callback);
|
||||
|
||||
bool connect_to_peer(bool is_v6, const char* ip, int port);
|
||||
|
||||
void drop_connections_async() { if (m_finished.load() == 0) { uv_async_send(&m_dropConnectionsAsync); } }
|
||||
@@ -47,12 +44,12 @@ public:
|
||||
bool connect_to_peer(bool is_v6, const raw_ip& ip, int port);
|
||||
virtual void on_connect_failed(bool /*is_v6*/, const raw_ip& /*ip*/, int /*port*/) {}
|
||||
|
||||
void ban(const raw_ip& ip, uint64_t seconds);
|
||||
void ban(bool is_v6, raw_ip ip, uint64_t seconds);
|
||||
virtual void print_bans();
|
||||
|
||||
struct Client
|
||||
{
|
||||
Client();
|
||||
Client(char* read_buf, size_t size);
|
||||
virtual ~Client() {}
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
@@ -73,7 +70,10 @@ public:
|
||||
|
||||
void init_addr_string();
|
||||
|
||||
alignas(8) char m_readBuf[READ_BUF_SIZE];
|
||||
void asan_poison_this() const;
|
||||
|
||||
char* m_readBuf;
|
||||
uint32_t m_readBufSize;
|
||||
|
||||
TCPServer* m_owner;
|
||||
|
||||
@@ -89,9 +89,13 @@ public:
|
||||
bool m_isClosing;
|
||||
uint32_t m_numRead;
|
||||
|
||||
enum {
|
||||
ADDR_STRING_SIZE = 72,
|
||||
};
|
||||
|
||||
raw_ip m_addr;
|
||||
int m_port;
|
||||
char m_addrString[72];
|
||||
char m_addrString[ADDR_STRING_SIZE];
|
||||
|
||||
enum class Socks5ProxyState {
|
||||
Default,
|
||||
@@ -110,34 +114,21 @@ public:
|
||||
size_t m_dataCapacity = 0;
|
||||
};
|
||||
|
||||
std::vector<WriteBuf*> m_writeBuffers;
|
||||
std::multimap<size_t, WriteBuf*> m_writeBuffers;
|
||||
|
||||
WriteBuf* get_write_buffer();
|
||||
WriteBuf* get_write_buffer(size_t size_hint);
|
||||
void return_write_buffer(WriteBuf* buf);
|
||||
|
||||
struct SendCallbackBase
|
||||
template<typename T>
|
||||
FORCEINLINE static void parse_address_list(const std::string& address_list, T&& callback)
|
||||
{
|
||||
virtual ~SendCallbackBase() {}
|
||||
virtual size_t operator()(void*, size_t) = 0;
|
||||
};
|
||||
return parse_address_list_internal(address_list, Callback<void, bool, const std::string&, const std::string&, int>::Derived<T>(std::move(callback)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct SendCallback : public SendCallbackBase
|
||||
{
|
||||
explicit FORCEINLINE SendCallback(T&& callback) : m_callback(std::move(callback)) {}
|
||||
size_t operator()(void* buf, size_t buf_size) override { return m_callback(buf, buf_size); }
|
||||
|
||||
private:
|
||||
SendCallback& operator=(SendCallback&&) = delete;
|
||||
|
||||
T m_callback;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE bool send(Client* client, T&& callback) { return send_internal(client, SendCallback<T>(std::move(callback))); }
|
||||
FORCEINLINE bool send(Client* client, T&& callback) { return send_internal(client, Callback<size_t, uint8_t*, size_t>::Derived<T>(std::move(callback))); }
|
||||
|
||||
private:
|
||||
static void loop(void* data);
|
||||
static void on_new_connection(uv_stream_t* server, int status);
|
||||
static void on_connection_close(uv_handle_t* handle);
|
||||
static void on_connection_error(uv_handle_t* handle);
|
||||
@@ -147,18 +138,30 @@ private:
|
||||
|
||||
bool connect_to_peer(Client* client);
|
||||
|
||||
bool send_internal(Client* client, SendCallbackBase&& callback);
|
||||
bool send_internal(Client* client, Callback<size_t, uint8_t*, size_t>::Base&& callback);
|
||||
|
||||
allocate_client_callback m_allocateNewClient;
|
||||
|
||||
void close_sockets(bool listen_sockets);
|
||||
static void error_invalid_ip(const std::string& address);
|
||||
|
||||
std::vector<uv_tcp_t*> m_listenSockets6;
|
||||
std::vector<uv_tcp_t*> m_listenSockets;
|
||||
uv_thread_t m_loopThread;
|
||||
|
||||
protected:
|
||||
virtual const char* get_log_category() const;
|
||||
|
||||
std::vector<uint8_t> m_callbackBuf;
|
||||
int m_defaultBacklog;
|
||||
|
||||
uv_thread_t m_loopThread;
|
||||
std::atomic<bool> m_loopThreadCreated;
|
||||
|
||||
static void loop(void* data);
|
||||
|
||||
static void parse_address_list_internal(const std::string& address_list, Callback<void, bool, const std::string&, const std::string&, int>::Base&& callback);
|
||||
void start_listening(const std::string& listen_addresses, bool upnp);
|
||||
bool start_listening(bool is_v6, const std::string& ip, int port, std::string address = std::string());
|
||||
|
||||
#ifdef WITH_UPNP
|
||||
int m_portMapping;
|
||||
@@ -175,7 +178,7 @@ protected:
|
||||
uv_loop_t m_loop;
|
||||
|
||||
#ifdef P2POOL_DEBUGGING
|
||||
static void check_event_loop_thread(const char *func);
|
||||
void check_event_loop_thread(const char *func) const;
|
||||
#else
|
||||
static FORCEINLINE void check_event_loop_thread(const char*) {}
|
||||
#endif
|
||||
@@ -192,7 +195,7 @@ protected:
|
||||
uv_mutex_t m_bansLock;
|
||||
unordered_map<raw_ip, std::chrono::steady_clock::time_point> m_bans;
|
||||
|
||||
bool is_banned(const raw_ip& ip);
|
||||
bool is_banned(bool is_v6, raw_ip ip);
|
||||
|
||||
unordered_set<raw_ip> m_pendingConnections;
|
||||
|
||||
|
||||
+133
-19
@@ -19,7 +19,8 @@
|
||||
#include "util.h"
|
||||
#include "uv_util.h"
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#if !defined(_WIN32) && defined(HAVE_SCHED)
|
||||
#include <sched.h>
|
||||
@@ -30,11 +31,26 @@
|
||||
#include "upnpcommands.h"
|
||||
#endif
|
||||
|
||||
static constexpr char log_category_prefix[] = "Util ";
|
||||
#ifdef _WIN32
|
||||
#include <WinDNS.h>
|
||||
#elif defined(HAVE_RES_QUERY)
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
|
||||
LOG_CATEGORY(Util)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MINOR) " (built"
|
||||
#if defined(P2POOL_VERSION_PATCH) && (P2POOL_VERSION_PATCH > 0)
|
||||
#define P2POOL_VERSION_PATCH_STR "." STR2(P2POOL_VERSION_PATCH)
|
||||
#else
|
||||
#define P2POOL_VERSION_PATCH_STR ""
|
||||
#endif
|
||||
|
||||
const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MINOR) P2POOL_VERSION_PATCH_STR " (built"
|
||||
#if defined(__clang__)
|
||||
" with clang/" __clang_version__
|
||||
#elif defined(__GNUC__)
|
||||
@@ -44,6 +60,25 @@ const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MIN
|
||||
#endif
|
||||
" on " __DATE__ ")";
|
||||
|
||||
SoftwareID get_software_id(uint32_t value)
|
||||
{
|
||||
switch (value) {
|
||||
case static_cast<uint32_t>(SoftwareID::P2Pool):
|
||||
return SoftwareID::P2Pool;
|
||||
|
||||
case static_cast<uint32_t>(SoftwareID::GoObserver):
|
||||
return SoftwareID::GoObserver;
|
||||
|
||||
default:
|
||||
return SoftwareID::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
const raw_ip raw_ip::localhost_ipv4 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 };
|
||||
const raw_ip raw_ip::localhost_ipv6 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
|
||||
|
||||
alignas(8) const uint8_t raw_ip::ipv4_prefix[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
|
||||
|
||||
MinerCallbackHandler::~MinerCallbackHandler() {}
|
||||
|
||||
void panic_stop(const char* message)
|
||||
@@ -126,7 +161,7 @@ NOINLINE difficulty_type& difficulty_type::operator/=(difficulty_type b)
|
||||
|
||||
NOINLINE bool difficulty_type::check_pow(const hash& pow_hash) const
|
||||
{
|
||||
const uint64_t* a = reinterpret_cast<const uint64_t*>(pow_hash.h);
|
||||
const uint64_t* a = pow_hash.u64();
|
||||
|
||||
uint64_t result[6] = {};
|
||||
uint64_t product[6] = {};
|
||||
@@ -308,9 +343,13 @@ struct BackgroundJobTracker::Impl
|
||||
{
|
||||
MutexLock lock(m_lock);
|
||||
|
||||
auto it = m_jobs.insert({ name, 1 });
|
||||
auto it = m_jobs.emplace(name, 1);
|
||||
if (!it.second) {
|
||||
++it.first->second;
|
||||
const int32_t n = ++it.first->second;
|
||||
// Print the warning only once as the number goes past 20
|
||||
if (n == 20) {
|
||||
LOGWARN(3, "Performance warning: there are " << n << " instances of " << name << " running in the background. This shouldn't be normally happening - check logs for other warnings and errors.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,8 +363,8 @@ struct BackgroundJobTracker::Impl
|
||||
return;
|
||||
}
|
||||
|
||||
--it->second;
|
||||
if (it->second <= 0) {
|
||||
const int32_t n = --it->second;
|
||||
if (n <= 0) {
|
||||
m_jobs.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -461,6 +500,78 @@ bool resolve_host(std::string& host, bool& is_v6)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_dns_txt_records_base(const std::string& host, Callback<void, const char*, size_t>::Base&& callback)
|
||||
{
|
||||
if (disable_resolve_host) {
|
||||
LOGERR(1, "get_dns_txt_records was called with DNS disabled for host " << host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
PDNS_RECORD pQueryResults;
|
||||
if (DnsQuery(host.c_str(), DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &pQueryResults, NULL) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (PDNS_RECORD p = pQueryResults; p; p = p->pNext) {
|
||||
for (size_t j = 0; j < p->Data.TXT.dwStringCount; ++j) {
|
||||
const char* s = p->Data.TXT.pStringArray[j];
|
||||
if (s) {
|
||||
const size_t n = strlen(s);
|
||||
if (n > 0) {
|
||||
callback(s, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DnsRecordListFree(pQueryResults, DnsFreeRecordList);
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif defined(HAVE_RES_QUERY)
|
||||
static const int res_init_result = res_init();
|
||||
if (res_init_result != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t answer[4096] = {};
|
||||
const int anslen = res_query(host.c_str(), ns_c_in, ns_t_txt, answer, sizeof(answer));
|
||||
if ((anslen <= 0) || (anslen > static_cast<int>(sizeof(answer)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ns_msg handle{};
|
||||
if (ns_initparse(answer, anslen, &handle) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int rrnum = 0, n = ns_msg_count(handle, ns_s_an); rrnum < n; ++rrnum) {
|
||||
ns_rr rr{};
|
||||
if ((ns_parserr(&handle, ns_s_an, rrnum, &rr) == 0) && (ns_rr_type(rr) == ns_t_txt)) {
|
||||
for (const uint8_t* data = ns_rr_rdata(rr), *e = data + ns_rr_rdlen(rr); data < e;) {
|
||||
const size_t k = *(data++);
|
||||
if (k && (data + k <= e)) {
|
||||
callback(reinterpret_cast<const char*>(data), k);
|
||||
}
|
||||
data += k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
(void)host;
|
||||
(void)callback;
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
RandomDeviceSeed RandomDeviceSeed::instance;
|
||||
|
||||
struct BSR8
|
||||
@@ -522,10 +633,8 @@ bool str_to_ip(bool is_v6, const char* ip, raw_ip& result)
|
||||
LOGERR(1, "failed to parse IPv4 address " << ip << ", error " << uv_err_name(err));
|
||||
return false;
|
||||
}
|
||||
result = {};
|
||||
result.data[10] = 0xFF;
|
||||
result.data[11] = 0xFF;
|
||||
memcpy(result.data + 12, &addr4->sin_addr, sizeof(in_addr));
|
||||
memcpy(result.data, raw_ip::ipv4_prefix, sizeof(raw_ip::ipv4_prefix));
|
||||
memcpy(result.data + sizeof(raw_ip::ipv4_prefix), &addr4->sin_addr, sizeof(in_addr));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -646,23 +755,26 @@ int add_portmapping(int external_port, int internal_port)
|
||||
LOGINFO(1, "UPnP: WAN IP address " << log::Gray() << static_cast<const char*>(ext_addr));
|
||||
}
|
||||
|
||||
const std::string eport = std::to_string(external_port);
|
||||
const std::string iport = std::to_string(internal_port);
|
||||
char eport[16] = {};
|
||||
do { log::Stream s(eport); s << external_port; } while (0);
|
||||
|
||||
result = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport.c_str(), iport.c_str(), local_addr, "P2Pool", "TCP", nullptr, nullptr);
|
||||
char iport[16] = {};
|
||||
do { log::Stream s(iport); s << internal_port; } while (0);
|
||||
|
||||
result = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, local_addr, "P2Pool", "TCP", nullptr, nullptr);
|
||||
|
||||
// ConflictInMappingEntry: try to delete the old record and then add the new one again
|
||||
if (result == 718) {
|
||||
LOGWARN(1, "UPNP_AddPortMapping failed: ConflictInMappingEntry");
|
||||
|
||||
result = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport.c_str(), "TCP", nullptr);
|
||||
result = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport, "TCP", nullptr);
|
||||
if (result) {
|
||||
LOGWARN(1, "UPNP_DeletePortMapping returned error " << result);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
LOGINFO(1, "UPnP: Deleted mapping for external port " << external_port);
|
||||
result = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport.c_str(), iport.c_str(), local_addr, "P2Pool", "TCP", nullptr, nullptr);
|
||||
result = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, local_addr, "P2Pool", "TCP", nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,8 +808,10 @@ void remove_portmapping(int external_port)
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string eport = std::to_string(external_port);
|
||||
result = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport.c_str(), "TCP", nullptr);
|
||||
char eport[16] = {};
|
||||
do { log::Stream s(eport); s << external_port; } while (0);
|
||||
|
||||
result = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport, "TCP", nullptr);
|
||||
if (result) {
|
||||
LOGWARN(1, "UPNP_DeletePortMapping returned error " << result);
|
||||
}
|
||||
|
||||
+51
-4
@@ -35,10 +35,19 @@
|
||||
namespace p2pool {
|
||||
|
||||
#define P2POOL_VERSION_MAJOR 3
|
||||
#define P2POOL_VERSION_MINOR 2
|
||||
#define P2POOL_VERSION_MINOR 9
|
||||
#define P2POOL_VERSION_PATCH 0
|
||||
|
||||
extern const char* VERSION;
|
||||
|
||||
enum class SoftwareID : uint32_t {
|
||||
P2Pool = 0,
|
||||
GoObserver = 0x624F6F47UL,
|
||||
Unknown = 0xFFFFFFFFUL,
|
||||
};
|
||||
|
||||
SoftwareID get_software_id(uint32_t value);
|
||||
|
||||
template<typename T> struct not_implemented { enum { value = 0 }; };
|
||||
|
||||
struct nocopy_nomove
|
||||
@@ -90,11 +99,17 @@ static FORCEINLINE bool from_hex(char c, T& out_value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, bool is_signed> struct is_negative_helper {};
|
||||
template<typename T> struct is_negative_helper<T, false> { static FORCEINLINE bool value(T) { return false; } };
|
||||
template<typename T> struct is_negative_helper<T, true> { static FORCEINLINE bool value(T x) { return (x < 0); } };
|
||||
|
||||
template<typename T> FORCEINLINE bool is_negative(T x) { return is_negative_helper<T, std::is_signed<T>::value>::value(x); }
|
||||
|
||||
template<typename T, bool is_signed> struct abs_helper {};
|
||||
template<typename T> struct abs_helper<T, false> { static FORCEINLINE T value(T x) { return x; } };
|
||||
template<typename T> struct abs_helper<T, true> { static FORCEINLINE T value(T x) { return (x >= 0) ? x : -x; } };
|
||||
template<typename T> struct abs_helper<T, true> { static FORCEINLINE std::make_unsigned_t<T> value(T x) { return (x < 0) ? -x : x; } };
|
||||
|
||||
template<typename T> FORCEINLINE T abs(T x) { return abs_helper<T, std::is_signed<T>::value>::value(x); }
|
||||
template<typename T> FORCEINLINE std::make_unsigned_t<T> abs(T x) { return abs_helper<T, std::is_signed<T>::value>::value(x); }
|
||||
|
||||
template<typename T, typename U>
|
||||
FORCEINLINE void writeVarint(T value, U&& callback)
|
||||
@@ -275,11 +290,43 @@ struct PerfTimer
|
||||
#define PERFLOG(level, name) PerfTimer CONCAT(perf_timer_, __LINE__)(level, name)
|
||||
#endif
|
||||
|
||||
template<typename R, typename ...Args>
|
||||
struct Callback
|
||||
{
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base() {}
|
||||
virtual R operator()(Args...) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Derived : public Base
|
||||
{
|
||||
explicit FORCEINLINE Derived(T&& cb) : m_cb(std::move(cb)) {}
|
||||
R operator()(Args... args) override { return m_cb(args...); }
|
||||
|
||||
private:
|
||||
Derived& operator=(Derived&&) = delete;
|
||||
T m_cb;
|
||||
};
|
||||
};
|
||||
|
||||
bool get_dns_txt_records_base(const std::string& host, Callback<void, const char*, size_t>::Base&& callback);
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE bool get_dns_txt_records(const std::string& host, T&& callback) { return get_dns_txt_records_base(host, Callback<void, const char*, size_t>::Derived<T>(std::move(callback))); }
|
||||
|
||||
#ifdef DEV_TRACK_MEMORY
|
||||
void show_top_10_allocations();
|
||||
#endif
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
void memory_tracking_start();
|
||||
void memory_tracking_stop();
|
||||
bool memory_tracking_stop();
|
||||
void p2pool_usage();
|
||||
void p2pool_version();
|
||||
int p2pool_test();
|
||||
|
||||
namespace robin_hood {
|
||||
|
||||
|
||||
+2
-17
@@ -64,22 +64,7 @@ void uv_rwlock_init_checked(uv_rwlock_t* lock);
|
||||
void uv_async_init_checked(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb);
|
||||
uv_loop_t* uv_default_loop_checked();
|
||||
|
||||
struct UV_LoopCallbackBase
|
||||
{
|
||||
virtual ~UV_LoopCallbackBase() {}
|
||||
virtual void operator()() = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct UV_LoopCallback : public UV_LoopCallbackBase
|
||||
{
|
||||
explicit FORCEINLINE UV_LoopCallback(T&& cb) : m_cb(std::move(cb)) {}
|
||||
void operator()() override { m_cb(); }
|
||||
|
||||
private:
|
||||
UV_LoopCallback& operator=(UV_LoopCallback&&) = delete;
|
||||
T m_cb;
|
||||
};
|
||||
typedef Callback<void>::Base UV_LoopCallbackBase;
|
||||
|
||||
struct UV_LoopUserData
|
||||
{
|
||||
@@ -147,7 +132,7 @@ bool CallOnLoop(uv_loop_t* loop, T&& callback)
|
||||
return false;
|
||||
}
|
||||
|
||||
UV_LoopCallbackBase* cb = new UV_LoopCallback<T>(std::move(callback));
|
||||
UV_LoopCallbackBase* cb = new Callback<void>::Derived<T>(std::move(callback));
|
||||
{
|
||||
MutexLock lock(data->m_callbacksLock);
|
||||
data->m_callbacks.push_back(cb);
|
||||
|
||||
+94
-40
@@ -20,12 +20,12 @@
|
||||
#include "json_parsers.h"
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
static constexpr char log_category_prefix[] = "ZMQReader ";
|
||||
LOG_CATEGORY(ZMQReader)
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::string& proxy, MinerCallbackHandler* handler)
|
||||
: m_address(address)
|
||||
: m_monitor(nullptr)
|
||||
, m_zmqPort(zmq_port)
|
||||
, m_proxy(proxy)
|
||||
, m_handler(handler)
|
||||
@@ -38,18 +38,20 @@ ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::s
|
||||
m_proxy.clear();
|
||||
}
|
||||
|
||||
for (uint32_t i = m_publisherPort; i < std::numeric_limits<uint16_t>::max(); ++i) {
|
||||
try {
|
||||
m_publisherPort = 0;
|
||||
char addr_buf[log::Stream::BUF_SIZE + 1];
|
||||
addr_buf[0] = '\0';
|
||||
|
||||
char addr[32];
|
||||
snprintf(addr, sizeof(addr), "tcp://127.0.0.1:%u", i);
|
||||
m_publisher.bind(addr);
|
||||
m_publisherPort = static_cast<uint16_t>(i);
|
||||
std::random_device rd;
|
||||
for (uint32_t port = 49152 + (rd() % 16384), i = 0; i < 100; ++i, port = (port < 65535) ? (port + 1) : 49152) {
|
||||
try {
|
||||
log::Stream s(addr_buf);
|
||||
s << "tcp://127.0.0.1:" << port << '\0';
|
||||
m_publisher.bind(addr_buf);
|
||||
m_publisherPort = static_cast<uint16_t>(port);
|
||||
break;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGWARN(1, "failed to to bind port " << i << " for ZMQ publisher, error " << e.what());
|
||||
LOGWARN(1, "failed to to bind port " << port << " for ZMQ publisher, error " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,31 +60,37 @@ ZMQReader::ZMQReader(const std::string& address, uint32_t zmq_port, const std::s
|
||||
throw zmq::error_t(EFSM);
|
||||
}
|
||||
|
||||
LOGINFO(5, "listening on tcp://127.0.0.1:" << m_publisherPort << " for internal communications");
|
||||
|
||||
m_subscriber.set(zmq::sockopt::connect_timeout, 1000);
|
||||
|
||||
std::string addr(addr_buf);
|
||||
if (!connect(addr, false)) {
|
||||
throw zmq::error_t(EFSM);
|
||||
}
|
||||
|
||||
if (!m_proxy.empty()) {
|
||||
m_subscriber.set(zmq::sockopt::socks_proxy, zmq::const_buffer(m_proxy.c_str(), m_proxy.length()));
|
||||
}
|
||||
|
||||
std::string addr = "tcp://" + m_address + ':' + std::to_string(m_zmqPort);
|
||||
if (!connect(addr)) {
|
||||
log::Stream s(addr_buf);
|
||||
s << "tcp://" << address << ':' << m_zmqPort << '\0';
|
||||
addr.assign(addr_buf);
|
||||
|
||||
if (!connect(addr, true)) {
|
||||
throw zmq::error_t(EFSM);
|
||||
}
|
||||
m_address = std::move(addr);
|
||||
|
||||
m_subscriber.set(zmq::sockopt::socks_proxy, zmq::const_buffer());
|
||||
|
||||
addr = "tcp://127.0.0.1:" + std::to_string(m_publisherPort);
|
||||
if (!connect(addr)) {
|
||||
throw zmq::error_t(EFSM);
|
||||
}
|
||||
|
||||
m_subscriber.set(zmq::sockopt::subscribe, "json-full-chain_main");
|
||||
m_subscriber.set(zmq::sockopt::subscribe, "json-full-miner_data");
|
||||
m_subscriber.set(zmq::sockopt::subscribe, "json-minimal-txpool_add");
|
||||
|
||||
const int err = uv_thread_create(&m_worker, run_wrapper, this);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to start ZMQ thread, error " << uv_err_name(err));
|
||||
LOGERR(1, "failed to start ZMQ worker thread, error " << uv_err_name(err));
|
||||
throw zmq::error_t(EMTHREAD);
|
||||
}
|
||||
}
|
||||
@@ -91,18 +99,43 @@ ZMQReader::~ZMQReader()
|
||||
{
|
||||
LOGINFO(1, "stopping");
|
||||
|
||||
m_finished.exchange(true);
|
||||
stop();
|
||||
uv_thread_join(&m_worker);
|
||||
|
||||
delete m_monitor;
|
||||
|
||||
LOGINFO(1, "stopped");
|
||||
}
|
||||
|
||||
void ZMQReader::stop()
|
||||
{
|
||||
if (m_stopped.exchange(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const char msg[] = "json-minimal-txpool_add:[]";
|
||||
m_publisher.send(zmq::const_buffer(msg, sizeof(msg) - 1));
|
||||
uv_thread_join(&m_worker);
|
||||
static constexpr char dummy_msg[] = "json-minimal-txpool_add:[]";
|
||||
m_publisher.send(zmq::const_buffer(dummy_msg, sizeof(dummy_msg) - 1));
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
LOGERR(1, "exception " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void ZMQReader::monitor_thread(void* arg)
|
||||
{
|
||||
LOGINFO(1, "monitor thread ready");
|
||||
|
||||
ZMQReader* r = reinterpret_cast<ZMQReader*>(arg);
|
||||
|
||||
do {} while (!r->m_stopped && r->m_monitor->m_connected && r->m_monitor->check_event(-1));
|
||||
|
||||
// If not connected anymore, shut down ZMQReader entirely
|
||||
r->stop();
|
||||
|
||||
LOGINFO(1, "monitor thread stopped");
|
||||
}
|
||||
|
||||
void ZMQReader::run_wrapper(void* arg)
|
||||
{
|
||||
reinterpret_cast<ZMQReader*>(arg)->run();
|
||||
@@ -111,8 +144,8 @@ void ZMQReader::run_wrapper(void* arg)
|
||||
|
||||
void ZMQReader::run()
|
||||
{
|
||||
m_threadRunning = true;
|
||||
ON_SCOPE_LEAVE([this]() { m_threadRunning = false; });
|
||||
m_workerThreadRunning = true;
|
||||
ON_SCOPE_LEAVE([this]() { m_workerThreadRunning = false; });
|
||||
|
||||
zmq_msg_t message = {};
|
||||
|
||||
@@ -122,6 +155,17 @@ void ZMQReader::run()
|
||||
throw zmq::error_t(errno);
|
||||
}
|
||||
|
||||
const int err = uv_thread_create(&m_monitorThread, monitor_thread, this);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to start ZMQ monitor thread, error " << uv_err_name(err));
|
||||
throw zmq::error_t(EMTHREAD);
|
||||
}
|
||||
|
||||
ON_SCOPE_LEAVE([this]() {
|
||||
m_monitor->abort();
|
||||
uv_thread_join(&m_monitorThread);
|
||||
});
|
||||
|
||||
LOGINFO(1, "worker thread ready");
|
||||
|
||||
do {
|
||||
@@ -130,7 +174,7 @@ void ZMQReader::run()
|
||||
throw zmq::error_t(errno);
|
||||
}
|
||||
|
||||
if (m_finished.load()) {
|
||||
if (m_stopped) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -144,19 +188,20 @@ void ZMQReader::run()
|
||||
zmq_msg_close(&message);
|
||||
}
|
||||
|
||||
bool ZMQReader::connect(const std::string& address)
|
||||
void ZMQReader::Monitor::on_event_connected(const zmq_event_t&, const char* address)
|
||||
{
|
||||
struct ConnectMonitor : public zmq::monitor_t
|
||||
{
|
||||
void on_event_connected(const zmq_event_t&, const char* address) ZMQ_OVERRIDE
|
||||
{
|
||||
LOGINFO(1, "connected to " << address);
|
||||
connected = true;
|
||||
}
|
||||
LOGINFO(1, "connected to " << address);
|
||||
m_connected = true;
|
||||
}
|
||||
|
||||
bool connected = false;
|
||||
} monitor;
|
||||
void ZMQReader::Monitor::on_event_disconnected(const zmq_event_t&, const char* address)
|
||||
{
|
||||
LOGERR(1, "disconnected from " << address);
|
||||
m_connected = false;
|
||||
}
|
||||
|
||||
bool ZMQReader::connect(const std::string& address, bool keep_monitor)
|
||||
{
|
||||
static uint64_t id = 0;
|
||||
|
||||
if (!id) {
|
||||
@@ -164,7 +209,7 @@ bool ZMQReader::connect(const std::string& address)
|
||||
id = (static_cast<uint64_t>(rd()) << 32) | static_cast<uint32_t>(rd());
|
||||
}
|
||||
|
||||
char buf[log::Stream::BUF_SIZE + 1];
|
||||
char buf[64];
|
||||
log::Stream s(buf);
|
||||
s << "inproc://p2pool-connect-mon-" << id << '\0';
|
||||
++id;
|
||||
@@ -172,23 +217,32 @@ bool ZMQReader::connect(const std::string& address)
|
||||
using namespace std::chrono;
|
||||
const auto start_time = steady_clock::now();
|
||||
|
||||
monitor.init(m_subscriber, buf);
|
||||
Monitor* monitor = new Monitor();
|
||||
monitor->init(m_subscriber, buf);
|
||||
m_subscriber.connect(address);
|
||||
|
||||
while (!monitor.connected && monitor.check_event(-1)) {
|
||||
while (!monitor->m_connected && monitor->check_event(-1)) {
|
||||
if (duration_cast<milliseconds>(steady_clock::now() - start_time).count() >= 1000) {
|
||||
LOGERR(1, "failed to connect to " << address);
|
||||
delete monitor;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (keep_monitor) {
|
||||
m_monitor = monitor;
|
||||
}
|
||||
else {
|
||||
delete monitor;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZMQReader::parse(char* data, size_t size)
|
||||
{
|
||||
char* value = data;
|
||||
char* end = data + size;
|
||||
const char* end = data + size;
|
||||
|
||||
while ((value < end) && (*value != ':')) {
|
||||
++value;
|
||||
@@ -205,7 +259,7 @@ void ZMQReader::parse(char* data, size_t size)
|
||||
using namespace rapidjson;
|
||||
|
||||
Document doc;
|
||||
if (doc.Parse<kParseCommentsFlag | kParseTrailingCommasFlag>(value, end - value).HasParseError()) {
|
||||
if (doc.Parse(value, end - value).HasParseError()) {
|
||||
LOGWARN(1, "ZeroMQ message failed to parse, skipping it");
|
||||
return;
|
||||
}
|
||||
|
||||
+22
-5
@@ -27,12 +27,29 @@ public:
|
||||
ZMQReader(const std::string& address, uint32_t zmq_port, const std::string& proxy, MinerCallbackHandler* handler);
|
||||
~ZMQReader();
|
||||
|
||||
bool is_running() const { return m_threadRunning.load(); }
|
||||
bool is_running() const { return m_workerThreadRunning.load(); }
|
||||
|
||||
private:
|
||||
struct Monitor : public zmq::monitor_t {
|
||||
Monitor() : m_connected(false) {}
|
||||
Monitor(const Monitor&) = delete;
|
||||
|
||||
void on_event_connected(const zmq_event_t&, const char* address) ZMQ_OVERRIDE;
|
||||
void on_event_disconnected(const zmq_event_t&, const char* address) ZMQ_OVERRIDE;
|
||||
|
||||
std::atomic<bool> m_connected;
|
||||
} *m_monitor;
|
||||
|
||||
static void monitor_thread(void* arg);
|
||||
|
||||
uv_thread_t m_monitorThread{};
|
||||
|
||||
private:
|
||||
void stop();
|
||||
|
||||
static void run_wrapper(void* arg);
|
||||
void run();
|
||||
bool connect(const std::string& address);
|
||||
bool connect(const std::string& address, bool keep_monitor);
|
||||
|
||||
void parse(char* data, size_t size);
|
||||
|
||||
@@ -45,9 +62,9 @@ private:
|
||||
zmq::context_t m_context{ 1 };
|
||||
zmq::socket_t m_publisher{ m_context, ZMQ_PUB };
|
||||
zmq::socket_t m_subscriber{ m_context, ZMQ_SUB };
|
||||
uint16_t m_publisherPort = 37891;
|
||||
std::atomic<bool> m_finished{ false };
|
||||
std::atomic<bool> m_threadRunning{ false };
|
||||
uint16_t m_publisherPort = 0;
|
||||
std::atomic<bool> m_stopped{ false };
|
||||
std::atomic<bool> m_workerThreadRunning{ false };
|
||||
|
||||
TxMempoolData m_tx;
|
||||
MinerData m_minerData;
|
||||
|
||||
+17
-10
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(p2pool_tests)
|
||||
|
||||
option(STATIC_LIBS "Use locally built libuv and libzmq static libs" OFF)
|
||||
@@ -9,6 +9,9 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.5.2")
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT p2pool_tests)
|
||||
endif()
|
||||
|
||||
set(BUILD_GMOCK OFF CACHE BOOL "Builds the googlemock subproject" FORCE)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" FORCE)
|
||||
|
||||
add_subdirectory(googletest)
|
||||
set(LIBS gtest)
|
||||
|
||||
@@ -30,6 +33,7 @@ set(SOURCES
|
||||
src/difficulty_type_tests.cpp
|
||||
src/hash_tests.cpp
|
||||
src/keccak_tests.cpp
|
||||
src/log_tests.cpp
|
||||
src/main.cpp
|
||||
src/pool_block_tests.cpp
|
||||
src/util_tests.cpp
|
||||
@@ -55,6 +59,7 @@ set(SOURCES
|
||||
../src/pow_hash.cpp
|
||||
../src/side_chain.cpp
|
||||
../src/stratum_server.cpp
|
||||
../src/tcp_server.cpp
|
||||
../src/util.cpp
|
||||
../src/wallet.cpp
|
||||
../src/zmq_reader.cpp
|
||||
@@ -91,8 +96,8 @@ include_directories(src)
|
||||
include_directories(googletest/googletest/include)
|
||||
|
||||
if (WIN32)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi wldap32)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi dnsapi dbghelp)
|
||||
if ((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
|
||||
set(LIBS ${LIBS} bcrypt)
|
||||
endif()
|
||||
add_definitions(-DCURL_STATICLIB)
|
||||
@@ -103,17 +108,17 @@ endif()
|
||||
if (STATIC_LIBS)
|
||||
set(ZMQ_LIBRARY "${CMAKE_SOURCE_DIR}/../external/src/libzmq/build/lib/libzmq.a")
|
||||
set(ZMQ_LIBRARY_DEBUG "${CMAKE_SOURCE_DIR}/../external/src/libzmq/build/lib/libzmq.a")
|
||||
set(UV_LIBRARY_DEBUG "${CMAKE_SOURCE_DIR}/../external/src/libuv/build/libuv_a.a")
|
||||
set(UV_LIBRARY "${CMAKE_SOURCE_DIR}/../external/src/libuv/build/libuv_a.a")
|
||||
set(UV_LIBRARY_DEBUG "${CMAKE_SOURCE_DIR}/../external/src/libuv/build/libuv.a")
|
||||
set(UV_LIBRARY "${CMAKE_SOURCE_DIR}/../external/src/libuv/build/libuv.a")
|
||||
set(CURL_LIBRARY_DEBUG "${CMAKE_SOURCE_DIR}/../external/src/curl/lib/.libs/libcurl.a")
|
||||
set(CURL_LIBRARY "${CMAKE_SOURCE_DIR}/../external/src/curl/lib/.libs/libcurl.a")
|
||||
else()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
find_library(ZMQ_LIBRARY_DEBUG NAMES libzmq-v142-mt-sgd-4_3_5 PATHS "../external/lib/libzmq/Debug")
|
||||
find_library(ZMQ_LIBRARY NAMES libzmq-v142-mt-s-4_3_5 PATHS "../external/lib/libzmq/Release")
|
||||
find_library(UV_LIBRARY_DEBUG NAMES uv_a PATHS "../external/lib/libuv/Debug")
|
||||
find_library(UV_LIBRARY NAMES uv_a PATHS "../external/lib/libuv/Release")
|
||||
find_library(CURL_LIBRARY_DEBUG NAMES libcurld PATHS "../external/lib/libcurl/Debug")
|
||||
find_library(UV_LIBRARY_DEBUG NAMES libuv PATHS "../external/lib/libuv/Debug")
|
||||
find_library(UV_LIBRARY NAMES libuv PATHS "../external/lib/libuv/Release")
|
||||
find_library(CURL_LIBRARY_DEBUG NAMES libcurl-d PATHS "../external/lib/libcurl/Debug")
|
||||
find_library(CURL_LIBRARY NAMES libcurl PATHS "../external/lib/libcurl/Release")
|
||||
add_definitions(-D_DISABLE_VECTOR_ANNOTATION)
|
||||
add_definitions(-D_DISABLE_STRING_ANNOTATION)
|
||||
@@ -170,9 +175,11 @@ if (HAVE_BITSCANREVERSE64)
|
||||
add_definitions(/DHAVE_BITSCANREVERSE64)
|
||||
endif()
|
||||
|
||||
add_definitions("-DRAPIDJSON_PARSE_DEFAULT_FLAGS=kParseTrailingCommasFlag")
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} debug ${CURL_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} optimized ${CURL_LIBRARY} ${LIBS})
|
||||
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/src/crypto_tests.txt" $<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/block.dat" $<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.dat" $<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" $<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.dat.gz" $<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.gz" $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>)
|
||||
|
||||
@@ -27,7 +27,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(GENERAL_FLAGS "")
|
||||
set(WARNING_FLAGS "/Wall /sdl")
|
||||
set(WARNING_FLAGS "/W4 /sdl")
|
||||
set(SECURITY_FLAGS "/GS /guard:cf")
|
||||
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
|
||||
|
||||
@@ -41,7 +41,12 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
|
||||
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
if (WIN32)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
else()
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
endif()
|
||||
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants -flto")
|
||||
|
||||
|
||||
+1
-1
Submodule tests/googletest updated: 58d77fa807...f8d7d77c06
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
@@ -74,8 +74,8 @@ TEST(block_template, update)
|
||||
ASSERT_EQ(diff, 300346053753ULL);
|
||||
ASSERT_EQ(sidechain_diff, sidechain.difficulty());
|
||||
ASSERT_EQ(seed_hash, data.seed_hash);
|
||||
ASSERT_EQ(nonce_offset, 39);
|
||||
ASSERT_EQ(template_id, 1);
|
||||
ASSERT_EQ(nonce_offset, 39U);
|
||||
ASSERT_EQ(template_id, 1U);
|
||||
|
||||
hash blobs_hash;
|
||||
keccak(blobs.data(), static_cast<int>(blobs.size()), blobs_hash.h);
|
||||
@@ -92,6 +92,7 @@ TEST(block_template, update)
|
||||
|
||||
tpl.update(data, mempool, &wallet);
|
||||
|
||||
ASSERT_EQ(b->m_sidechainId, H("272a7eea0b804cf24427528977d221850d0ee06c26e935219a75f180cfbfc7f3"));
|
||||
ASSERT_EQ(b->m_transactions.size(), 203);
|
||||
|
||||
for (size_t i = 1; i < b->m_transactions.size(); ++i) {
|
||||
@@ -104,8 +105,8 @@ TEST(block_template, update)
|
||||
ASSERT_EQ(diff, 300346053753ULL);
|
||||
ASSERT_EQ(sidechain_diff, sidechain.difficulty());
|
||||
ASSERT_EQ(seed_hash, data.seed_hash);
|
||||
ASSERT_EQ(nonce_offset, 39);
|
||||
ASSERT_EQ(template_id, 2);
|
||||
ASSERT_EQ(nonce_offset, 39U);
|
||||
ASSERT_EQ(template_id, 2U);
|
||||
|
||||
keccak(blobs.data(), static_cast<int>(blobs.size()), blobs_hash.h);
|
||||
ASSERT_EQ(blobs_hash, H("c74d295a9cb7e808030284e2169a6f05b685a11c6c577a774d5eb8fad175d5cd"));
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
# This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
# Copyright (c) 2021-2023 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/>.
|
||||
|
||||
import sys
|
||||
|
||||
allowedAPIs = {
|
||||
"getaddrinfo",
|
||||
"freeaddrinfo",
|
||||
"WSAPoll",
|
||||
"WSACreateEvent",
|
||||
"WSACloseEvent",
|
||||
"WSARecvFrom",
|
||||
"WSASend",
|
||||
"WSARecv",
|
||||
"WSADuplicateSocketW",
|
||||
"WSASocketW",
|
||||
"WSAIoctl",
|
||||
"getnameinfo",
|
||||
"WSASocketA",
|
||||
"GetAdaptersAddresses",
|
||||
"GetBestInterface",
|
||||
"DnsFree",
|
||||
"LoadLibraryExW",
|
||||
"RtlPcToFileHeader",
|
||||
"RtlUnwindEx",
|
||||
"GetCPInfo",
|
||||
"GetStringTypeW",
|
||||
"GetDriveTypeW",
|
||||
"DecodePointer",
|
||||
"EncodePointer",
|
||||
"FreeLibraryAndExitThread",
|
||||
"SystemTimeToTzSpecificLocalTime",
|
||||
"CreateThread",
|
||||
"LCMapStringEx",
|
||||
"ExitThread",
|
||||
"GetModuleHandleExW",
|
||||
"SetStdHandle",
|
||||
"FlsFree",
|
||||
"FlsSetValue",
|
||||
"FlsGetValue",
|
||||
"SetFilePointer",
|
||||
"SetEndOfFile",
|
||||
"UnmapViewOfFile",
|
||||
"GetLastError",
|
||||
"FlushViewOfFile",
|
||||
"CreateFileA",
|
||||
"CloseHandle",
|
||||
"CreateFileMappingA",
|
||||
"MapViewOfFile",
|
||||
"FlushFileBuffers",
|
||||
"GetStdHandle",
|
||||
"WriteConsoleA",
|
||||
"SetConsoleMode",
|
||||
"GetConsoleMode",
|
||||
"FormatMessageA",
|
||||
"SetThreadPriority",
|
||||
"GetCurrentThread",
|
||||
"SetThreadPriorityBoost",
|
||||
"IsDebuggerPresent",
|
||||
"Sleep",
|
||||
"RaiseException",
|
||||
"InitializeCriticalSection",
|
||||
"EnterCriticalSection",
|
||||
"LeaveCriticalSection",
|
||||
"DeleteCriticalSection",
|
||||
"QueryPerformanceCounter",
|
||||
"QueryPerformanceFrequency",
|
||||
"GetTickCount",
|
||||
"FreeLibrary",
|
||||
"GetProcAddress",
|
||||
"LoadLibraryA",
|
||||
"SetHandleInformation",
|
||||
"WaitForSingleObject",
|
||||
"GetCurrentThreadId",
|
||||
"TryEnterCriticalSection",
|
||||
"GetCurrentProcessId",
|
||||
"GetHandleInformation",
|
||||
"SetLastError",
|
||||
"CreateIoCompletionPort",
|
||||
"GetQueuedCompletionStatusEx",
|
||||
"InitializeSRWLock",
|
||||
"ReleaseSRWLockExclusive",
|
||||
"ReleaseSRWLockShared",
|
||||
"AcquireSRWLockExclusive",
|
||||
"AcquireSRWLockShared",
|
||||
"InitOnceExecuteOnce",
|
||||
"GetTickCount64",
|
||||
"GetModuleHandleW",
|
||||
"SetFileCompletionNotificationModes",
|
||||
"WideCharToMultiByte",
|
||||
"DuplicateHandle",
|
||||
"TryAcquireSRWLockShared",
|
||||
"InitializeConditionVariable",
|
||||
"WakeConditionVariable",
|
||||
"WakeAllConditionVariable",
|
||||
"SleepConditionVariableCS",
|
||||
"SetEvent",
|
||||
"ReleaseSemaphore",
|
||||
"CreateEventA",
|
||||
"GetCurrentProcess",
|
||||
"ResumeThread",
|
||||
"TlsAlloc",
|
||||
"TlsGetValue",
|
||||
"TlsSetValue",
|
||||
"TlsFree",
|
||||
"GetNativeSystemInfo",
|
||||
"CreateSemaphoreA",
|
||||
"GetFileType",
|
||||
"PostQueuedCompletionStatus",
|
||||
"CreateFileW",
|
||||
"ResetEvent",
|
||||
"QueueUserWorkItem",
|
||||
"GetFileAttributesExW",
|
||||
"UnregisterWait",
|
||||
"GetNumberOfConsoleInputEvents",
|
||||
"ReadConsoleInputW",
|
||||
"ReadConsoleW",
|
||||
"WriteConsoleW",
|
||||
"FillConsoleOutputCharacterW",
|
||||
"FillConsoleOutputAttribute",
|
||||
"GetConsoleCursorInfo",
|
||||
"SetConsoleCursorInfo",
|
||||
"GetConsoleScreenBufferInfo",
|
||||
"SetConsoleCursorPosition",
|
||||
"SetConsoleTextAttribute",
|
||||
"WriteConsoleInputW",
|
||||
"ReadFile",
|
||||
"WriteFile",
|
||||
"ConnectNamedPipe",
|
||||
"SetNamedPipeHandleState",
|
||||
"PeekNamedPipe",
|
||||
"CreateNamedPipeW",
|
||||
"CancelIoEx",
|
||||
"CancelSynchronousIo",
|
||||
"SwitchToThread",
|
||||
"LocalFree",
|
||||
"GetNamedPipeHandleStateA",
|
||||
"GetNamedPipeClientProcessId",
|
||||
"GetNamedPipeServerProcessId",
|
||||
"MultiByteToWideChar",
|
||||
"SetConsoleCtrlHandler",
|
||||
"SetErrorMode",
|
||||
"GetQueuedCompletionStatus",
|
||||
"CreateDirectoryW",
|
||||
"FindClose",
|
||||
"FindFirstFileW",
|
||||
"FindNextFileW",
|
||||
"RtlUnwind",
|
||||
"GetFileAttributesW",
|
||||
"GetFileInformationByHandle",
|
||||
"GetFileSizeEx",
|
||||
"GetFinalPathNameByHandleW",
|
||||
"GetFullPathNameW",
|
||||
"RemoveDirectoryW",
|
||||
"SetFilePointerEx",
|
||||
"SetFileTime",
|
||||
"DeviceIoControl",
|
||||
"GetSystemInfo",
|
||||
"GetSystemTimeAsFileTime",
|
||||
"ReOpenFile",
|
||||
"CopyFileW",
|
||||
"MoveFileExW",
|
||||
"CreateHardLinkW",
|
||||
"GetFileInformationByHandleEx",
|
||||
"CreateSymbolicLinkW",
|
||||
"CancelIo",
|
||||
"DebugBreak",
|
||||
"GetCurrentDirectoryW",
|
||||
"TerminateProcess",
|
||||
"GetExitCodeProcess",
|
||||
"UnregisterWaitEx",
|
||||
"LCMapStringW",
|
||||
"GetLongPathNameW",
|
||||
"ReadDirectoryChangesW",
|
||||
"GetEnvironmentStringsW",
|
||||
"FreeEnvironmentStringsW",
|
||||
"SetEnvironmentVariableW",
|
||||
"GetModuleFileNameW",
|
||||
"FileTimeToSystemTime",
|
||||
"GetModuleHandleA",
|
||||
"LoadLibraryExA",
|
||||
"GetStartupInfoW",
|
||||
"FormatMessageW",
|
||||
"InitializeCriticalSectionEx",
|
||||
"GetSystemDirectoryA",
|
||||
"WaitForSingleObjectEx",
|
||||
"GetEnvironmentVariableA",
|
||||
"SleepEx",
|
||||
"VerSetConditionMask",
|
||||
"VerifyVersionInfoW",
|
||||
"VirtualProtect",
|
||||
"VirtualFree",
|
||||
"VirtualAlloc",
|
||||
"GetLargePageMinimum",
|
||||
"HeapFree",
|
||||
"HeapAlloc",
|
||||
"GetProcessHeap",
|
||||
"FlsAlloc",
|
||||
"SleepConditionVariableSRW",
|
||||
"GetExitCodeThread",
|
||||
"InitializeSListHead",
|
||||
"CreateEventW",
|
||||
"InitializeCriticalSectionAndSpinCount",
|
||||
"IsProcessorFeaturePresent",
|
||||
"SetUnhandledExceptionFilter",
|
||||
"UnhandledExceptionFilter",
|
||||
"RtlVirtualUnwind",
|
||||
"RtlLookupFunctionEntry",
|
||||
"SetFileAttributesW",
|
||||
"GetConsoleOutputCP",
|
||||
"ExitProcess",
|
||||
"GetCommandLineA",
|
||||
"GetCommandLineW",
|
||||
"GetDateFormatW",
|
||||
"GetTimeFormatW",
|
||||
"CompareStringW",
|
||||
"GetLocaleInfoW",
|
||||
"IsValidLocale",
|
||||
"GetUserDefaultLCID",
|
||||
"EnumSystemLocalesW",
|
||||
"HeapReAlloc",
|
||||
"HeapSize",
|
||||
"FindFirstFileExW",
|
||||
"IsValidCodePage",
|
||||
"GetACP",
|
||||
"GetOEMCP",
|
||||
"GetTimeZoneInformation",
|
||||
"RegisterWaitForSingleObject",
|
||||
"GetDiskFreeSpaceW",
|
||||
"RtlCaptureContext",
|
||||
"GetMessageA",
|
||||
"GetSystemMetrics",
|
||||
"MapVirtualKeyW",
|
||||
"DispatchMessageA",
|
||||
"TranslateMessage",
|
||||
"AdjustTokenPrivileges",
|
||||
"LookupPrivilegeValueA",
|
||||
"CryptDestroyHash",
|
||||
"CryptHashData",
|
||||
"CryptCreateHash",
|
||||
"CryptGetHashParam",
|
||||
"CryptReleaseContext",
|
||||
"CryptAcquireContextA",
|
||||
"SystemFunction036",
|
||||
"OpenProcessToken",
|
||||
"SetSecurityDescriptorDacl",
|
||||
"InitializeSecurityDescriptor",
|
||||
"BCryptGenRandom",
|
||||
"GetConsoleCP",
|
||||
}
|
||||
|
||||
f = open(sys.argv[1], 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
exit_code = 0
|
||||
count = 0
|
||||
|
||||
for line in lines:
|
||||
count += 1
|
||||
api = line[29:].strip()
|
||||
if api not in allowedAPIs:
|
||||
print('API call "{}" is not checked for Windows 7 compatibility. Check it and then add it to the list in tests/src/check_imports.py'.format(api))
|
||||
exit_code = 1
|
||||
|
||||
if exit_code == 0:
|
||||
print('{} imports checked successfully'.format(count))
|
||||
|
||||
sys.exit(exit_code)
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
@@ -567,8 +567,8 @@ TEST(difficulty_type, check_pow)
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
// Random difficulty between 300G and 400G
|
||||
difficulty_type diff{ 300000000000ull + (r() % 100000000000ull), 0 };
|
||||
hash h;
|
||||
diff.lo = 300000000000ull + (r() % 100000000000ull);
|
||||
diff.hi = 0;
|
||||
|
||||
// All zeros
|
||||
memset(h.h, 0, HASH_SIZE);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021-2023 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 "gtest/gtest.h"
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
TEST(log, stream)
|
||||
{
|
||||
constexpr int N = 63;
|
||||
|
||||
char buf[N + 1] = {};
|
||||
log::Stream s(buf);
|
||||
|
||||
for (int iter = 0; iter < 2; ++iter) {
|
||||
ASSERT_EQ(s.m_bufSize, N);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
s << ' ';
|
||||
|
||||
ASSERT_EQ(s.m_pos, i + 1);
|
||||
ASSERT_EQ(s.m_spilled, 0);
|
||||
}
|
||||
|
||||
s << ' ';
|
||||
|
||||
ASSERT_EQ(s.m_pos, N);
|
||||
ASSERT_EQ(s.m_spilled, 1);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
ASSERT_EQ(buf[i], ' ');
|
||||
}
|
||||
|
||||
ASSERT_EQ(buf[N], '\0');
|
||||
|
||||
s.reset(buf, N + 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(log, pad_right)
|
||||
{
|
||||
constexpr int N = 63;
|
||||
|
||||
char buf[N + 1] = {};
|
||||
log::Stream s(buf);
|
||||
|
||||
s << log::pad_right('1', N);
|
||||
|
||||
ASSERT_EQ(s.m_pos, N);
|
||||
ASSERT_EQ(s.m_spilled, 0);
|
||||
|
||||
ASSERT_EQ(buf[0], '1');
|
||||
|
||||
for (int i = 1; i < N; ++i) {
|
||||
ASSERT_EQ(buf[i], ' ');
|
||||
}
|
||||
|
||||
ASSERT_EQ(buf[N], '\0');
|
||||
}
|
||||
|
||||
template<typename T, bool hex>
|
||||
void check_number(T value)
|
||||
{
|
||||
constexpr size_t N = 64;
|
||||
|
||||
char buf[N];
|
||||
memset(buf, -1, N);
|
||||
log::Stream s(buf);
|
||||
s << log::BasedValue<T, hex ? 16 : 10>(value) << '\0';
|
||||
|
||||
char buf2[N];
|
||||
memset(buf2, -1, N);
|
||||
snprintf(buf2, N, hex ? "%llx" : (std::is_signed<T>::value ? "%lld" : "%llu"), value);
|
||||
|
||||
ASSERT_EQ(memcmp(buf, buf2, N), 0);
|
||||
}
|
||||
|
||||
TEST(log, numbers)
|
||||
{
|
||||
for (int64_t i = -1024; i <= 1024; ++i) {
|
||||
check_number<int64_t, false>(i);
|
||||
|
||||
if (i >= 0) {
|
||||
check_number<int64_t, true>(i);
|
||||
check_number<uint64_t, false>(i);
|
||||
check_number<uint64_t, true>(i);
|
||||
}
|
||||
}
|
||||
|
||||
check_number<int64_t, false>(std::numeric_limits<int64_t>::min());
|
||||
check_number<int64_t, false>(std::numeric_limits<int64_t>::max());
|
||||
check_number<int64_t, true>(std::numeric_limits<int64_t>::max());
|
||||
|
||||
check_number<uint64_t, false>(std::numeric_limits<uint64_t>::max());
|
||||
check_number<uint64_t, true>(std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2021-2023 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
|
||||
@@ -18,9 +18,11 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
void p2pool_usage() {}
|
||||
namespace p2pool { void set_main_thread(); }
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
p2pool::set_main_thread();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user