Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
+70
-16
@@ -63,7 +63,7 @@ jobs:
|
||||
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
|
||||
@@ -74,9 +74,9 @@ 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" -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: |
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
- 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
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
@@ -146,9 +146,9 @@ 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_CXX_COMPILER=aarch64-linux-gnu-g++ -DCMAKE_C_FLAGS="-Os" -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: |
|
||||
@@ -198,14 +198,14 @@ 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-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_FLAGS="-Os" -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: |
|
||||
@@ -314,14 +314,14 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake autoconf libtool automake
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake
|
||||
|
||||
- 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" -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: |
|
||||
@@ -366,6 +366,60 @@ jobs:
|
||||
name: p2pool-${{ matrix.os }}
|
||||
path: build/p2pool
|
||||
|
||||
build-macos-aarch64:
|
||||
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-11, macos-12]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_FLAGS='-Os -target arm64-apple-${{ matrix.os }}' -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 -target arm64-apple-${{ matrix.os }}' -DBUILD_TESTING=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-Os -target arm64-apple-${{ matrix.os }}' -DCMAKE_CXX_FLAGS='-Os -target arm64-apple-${{ matrix.os }}' -DWITH_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DWITH_PERF_TOOL=OFF
|
||||
make -j3
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_FLAGS='-target arm64-apple-${{ matrix.os }}' -DCMAKE_CXX_FLAGS='-target arm64-apple-${{ matrix.os }}' -DSTATIC_BINARY=ON -DARCH_ID=aarch64
|
||||
make -j3
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.os }}-aarch64
|
||||
path: build/p2pool
|
||||
|
||||
build-freebsd:
|
||||
|
||||
timeout-minutes: 75
|
||||
@@ -393,12 +447,12 @@ jobs:
|
||||
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" -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
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
name: clang-tidy
|
||||
|
||||
on: [push, 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 16
|
||||
sudo apt-get install -y clang-tidy-16
|
||||
clang-tidy-16 --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-16 -DCMAKE_CXX_COMPILER=clang++-16 -DDEV_CLANG_TIDY=ON
|
||||
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
cd src
|
||||
clang-tidy-16 *.cpp -p ../build -checks=-clang-diagnostic-undefined-internal -warnings-as-errors=* -header-filter=^[^\.]
|
||||
@@ -1,14 +1,23 @@
|
||||
name: cppcheck
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '57 0 * * *'
|
||||
|
||||
jobs:
|
||||
cppcheck-ubuntu:
|
||||
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 50
|
||||
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 +34,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: 50
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
@@ -59,9 +81,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
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Build libc++ for MemorySanitizer
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build-libcxx_msan:
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y git cmake ninja-build
|
||||
|
||||
- name: Install clang
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 16
|
||||
|
||||
- name: Build libcxx_msan
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/llvm/llvm-project -b release/16.x
|
||||
cd llvm-project
|
||||
mkdir build
|
||||
cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -DLLVM_USE_SANITIZER=MemoryWithOrigins
|
||||
ninja -C build cxx cxxabi
|
||||
cd build
|
||||
XZ_OPT=-e9 tar cfJ libcxx_msan.tar.xz include lib
|
||||
|
||||
- name: Archive libcxx_msan.tar.xz
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: libcxx_msan
|
||||
path: llvm-project/build/libcxx_msan.tar.xz
|
||||
+186
-15
@@ -1,9 +1,13 @@
|
||||
name: Sync test
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '17 0/3 * * *'
|
||||
|
||||
jobs:
|
||||
sync-test-ubuntu:
|
||||
sync-test-ubuntu-tsan:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -24,23 +28,186 @@ 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_TSAN=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12
|
||||
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 &
|
||||
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 --data-api data --local-api --loglevel 6
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data
|
||||
name: p2pool_ubuntu_data_tsan
|
||||
path: |
|
||||
build/p2pool.log
|
||||
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 libuv1-dev libzmq3-dev libsodium-dev libpgm-dev libnorm-dev libgss-dev libcurl4-openssl-dev libidn2-0-dev
|
||||
|
||||
- name: Install clang
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 16
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install libcxx_msan
|
||||
run: |
|
||||
mkdir /tmp/libcxx_msan
|
||||
cp tests/src/libcxx_msan.tar.xz /tmp/libcxx_msan
|
||||
cd /tmp/libcxx_msan
|
||||
tar xvf libcxx_msan.tar.xz
|
||||
|
||||
- name: Build libcurl
|
||||
run: |
|
||||
cd external/src/curl
|
||||
cmake . -DCMAKE_C_COMPILER=clang-16 -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-16 -DCMAKE_C_FLAGS='-fsanitize=memory -fsanitize-recover -fsanitize-memory-track-origins -Os -fno-omit-frame-pointer -g' -DBUILD_TESTING=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build libzmq
|
||||
run: |
|
||||
cd external/src/libzmq
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -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_TLS=OFF -DWITH_LIBSODIUM=OFF -DWITH_LIBBSD=OFF -DBUILD_TESTS=OFF -DWITH_DOCS=OFF -DENABLE_DRAFTS=OFF -DWITH_PERF_TOOL=OFF
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build p2pool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -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-16 -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 --data-api data --local-api --loglevel 6
|
||||
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
|
||||
|
||||
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_UBSAN=ON -DCMAKE_C_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12
|
||||
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 &
|
||||
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 --data-api data --local-api --loglevel 6
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool_ubuntu_data_ubsan
|
||||
path: |
|
||||
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
|
||||
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 --data-api data --local-api --loglevel 6
|
||||
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:
|
||||
@@ -65,11 +232,13 @@ jobs:
|
||||
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
|
||||
python ../tests/src/stratum_dummy.py 1 &
|
||||
python ../tests/src/stratum_dummy.py 2 &
|
||||
python ../tests/src/stratum_dummy.py 3 &
|
||||
./p2pool --host xmrnode.facspro.net --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --wallet 44MnN1f3Eto8DZYUWuE5XZNUtE3vcRzt2j6PzqWpPau34e6Cf4fAxt6X2MBmrm6F9YMEiMNjN6W4Shn4pLcfNAja621jwyg --data-api data --local-api --loglevel 6
|
||||
grep 'Synchronization finished successfully' p2pool.log
|
||||
|
||||
- name: Archive p2pool.log
|
||||
@@ -77,10 +246,10 @@ jobs:
|
||||
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
|
||||
@@ -102,17 +271,19 @@ jobs:
|
||||
& "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\msbuild" /m /p:Configuration=Debug p2pool.vcxproj
|
||||
|
||||
- name: Run p2pool
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
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-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 --data-api data --local-api --loglevel 6
|
||||
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/
|
||||
|
||||
+108
-13
@@ -8,6 +8,11 @@ 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)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -31,6 +36,26 @@ 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()
|
||||
|
||||
include(cmake/flags.cmake)
|
||||
|
||||
set(HEADERS
|
||||
@@ -95,7 +120,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,7 +154,7 @@ 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()
|
||||
@@ -143,9 +168,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 +218,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,13 +293,24 @@ 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()
|
||||
|
||||
if (WITH_RANDOMX)
|
||||
@@ -231,7 +322,7 @@ if (STATIC_BINARY OR STATIC_LIBS)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} ws2_32 iphlpapi userenv psapi wldap32)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} ws2_32 iphlpapi userenv psapi dnsapi dbghelp)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(STATIC_LIBS ${STATIC_LIBS} bcrypt)
|
||||
endif()
|
||||
@@ -246,9 +337,13 @@ 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}
|
||||
)
|
||||
|
||||
@@ -6,12 +6,6 @@ Pool status and monitoring pages can be found at https://p2pool.io/, https://p2p
|
||||
|
||||
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.
|
||||
|
||||
# P2Pool hardforked on March 18, 2023
|
||||
|
||||
P2Pool (not Monero!) hardforked to new consensus rules on March 18th at 21:00 UTC. The hardfork was necessary to improve P2Pool scalability and reduce the impact on Monero blockchain. You need to update to the latest P2Pool version to continue mining on P2Pool.
|
||||
|
||||
Reddit discussions: [original announcement](https://www.reddit.com/r/MoneroMining/comments/1095730/psa_p2pool_network_upgrade_aka_hardfork_on_march/), [final announcement](https://www.reddit.com/r/MoneroMining/comments/11tln6z/psa_p2pool_miners_update_to_the_latest_version/)
|
||||
|
||||
### Build Status
|
||||
|
||||

|
||||
@@ -24,6 +18,7 @@ Reddit discussions: [original announcement](https://www.reddit.com/r/MoneroMinin
|
||||
<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)
|
||||
@@ -46,7 +41,7 @@ Here's the comparison table of the different ways of mining. While pool mining i
|
||||
|-|-|-|-|-|-|-|-|
|
||||
|Centralized pool|Regular|0-3%|0.001-0.01 XMR|Yes|Less stable due to pool server outages|Pool admin controls your mined funds, what you mine and can execute network attacks|Only miner software is required
|
||||
|Solo|Rare|0%|0.6 XMR or more|No|As stable as your Monero node|100% under your control|Monero node + optional miner
|
||||
|**P2Pool**|Regular|0%|~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) + miner(s)
|
||||
|
||||
## Features
|
||||
|
||||
@@ -62,6 +57,7 @@ Here's the comparison table of the different ways of mining. While pool mining i
|
||||
* 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
|
||||
|
||||
|
||||
+23
-2
@@ -7,8 +7,26 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
|
||||
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-align -Wcast-qual -Wlogical-op -Wstrict-overflow=2 -Wundef -Wformat=2 -Wpointer-arith -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
|
||||
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")
|
||||
@@ -52,7 +70,10 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
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 (NOT DEV_WITH_MSAN)
|
||||
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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -34,4 +34,19 @@
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
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.
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
+1
-1
Submodule external/src/RandomX updated: df7ee038c4...59d1483ad7
Vendored
+1
-1
Submodule external/src/libuv updated: 55077af4b5...7bb8ba6afc
Vendored
+1
-1
Submodule external/src/rapidjson updated: 914b772dfd...678281bbdb
@@ -1325,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) {
|
||||
|
||||
+7
-13
@@ -204,7 +204,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;
|
||||
@@ -221,7 +221,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;
|
||||
@@ -436,19 +436,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");
|
||||
|
||||
@@ -140,7 +140,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;
|
||||
@@ -155,6 +155,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
|
||||
@@ -162,6 +164,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 }
|
||||
};
|
||||
|
||||
@@ -196,6 +199,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()) {
|
||||
@@ -203,6 +207,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()) {
|
||||
@@ -210,6 +215,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()) {
|
||||
@@ -217,6 +223,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()) {
|
||||
@@ -224,6 +231,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()) {
|
||||
@@ -234,6 +242,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()) {
|
||||
@@ -242,6 +263,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()) {
|
||||
@@ -270,6 +292,11 @@ static void do_exit(p2pool *m_pool, const char * /* args */)
|
||||
m_pool->stop();
|
||||
}
|
||||
|
||||
static void do_version(p2pool* /* m_pool */, const char* /* args */)
|
||||
{
|
||||
LOGINFO(0, log::LightCyan() << VERSION);
|
||||
}
|
||||
|
||||
void ConsoleCommands::allocCallback(uv_handle_t* handle, size_t /*suggested_size*/, uv_buf_t* buf)
|
||||
{
|
||||
ConsoleCommands* pThis = static_cast<ConsoleCommands*>(handle->data);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -174,7 +179,11 @@ CurlContext::CurlContext(const std::string& address, int port, const std::string
|
||||
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 +219,17 @@ 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());
|
||||
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 +242,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);
|
||||
@@ -365,6 +379,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 +388,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 +486,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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -20,15 +20,15 @@
|
||||
namespace p2pool {
|
||||
namespace JSONRPCRequest {
|
||||
|
||||
typedef Callback<void, const char*, size_t>::Base CallbackBase;
|
||||
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)
|
||||
{
|
||||
typedef Callback<void, const char*, size_t>::Derived<T> CallbackT;
|
||||
typedef Callback<void, const char*, size_t>::Derived<U> CallbackU;
|
||||
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);
|
||||
}
|
||||
|
||||
+37
-47
@@ -154,7 +154,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 +174,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 +223,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]);
|
||||
@@ -286,9 +290,9 @@ private:
|
||||
|
||||
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 +333,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 +365,7 @@ NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
|
||||
m_pos = 3;
|
||||
|
||||
*this << Cyan();
|
||||
writeCurrentTime();
|
||||
writeCurrentTime(*this);
|
||||
*this << NoColor() << ' ';
|
||||
}
|
||||
|
||||
@@ -364,53 +393,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)
|
||||
|
||||
@@ -65,7 +65,7 @@ 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");
|
||||
@@ -78,11 +78,13 @@ struct Stream
|
||||
size_t k = sizeof(buf);
|
||||
int w = m_numberWidth;
|
||||
|
||||
std::make_unsigned_t<T> udata = static_cast<std::make_unsigned_t<T>>(data);
|
||||
|
||||
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] = '-';
|
||||
@@ -105,8 +107,6 @@ 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;
|
||||
@@ -146,7 +146,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*>
|
||||
@@ -486,16 +492,19 @@ 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
|
||||
|
||||
#ifdef P2POOL_LOG_DISABLE
|
||||
|
||||
|
||||
+122
-97
@@ -38,6 +38,7 @@ static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
|
||||
|
||||
static constexpr int DEFAULT_BACKLOG = 16;
|
||||
static constexpr uint64_t DEFAULT_BAN_TIME = 600;
|
||||
static constexpr uint64_t PEER_REQUEST_DELAY = 60;
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
@@ -373,10 +374,10 @@ void P2PServer::update_peer_list()
|
||||
void P2PServer::send_peer_list_request(P2PClient* client, uint64_t cur_time)
|
||||
{
|
||||
// Send peer list requests at random intervals (60-120 seconds)
|
||||
client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61));
|
||||
client->m_nextOutgoingPeerListRequest = cur_time + (PEER_REQUEST_DELAY + (get_random64() % (PEER_REQUEST_DELAY + 1)));
|
||||
|
||||
const bool result = send(client,
|
||||
[client](void* buf, size_t buf_size)
|
||||
[client](uint8_t* buf, size_t buf_size)
|
||||
{
|
||||
LOGINFO(6, "sending PEER_LIST_REQUEST to " << static_cast<char*>(client->m_addrString));
|
||||
|
||||
@@ -384,7 +385,7 @@ void P2PServer::send_peer_list_request(P2PClient* client, uint64_t cur_time)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*reinterpret_cast<uint8_t*>(buf) = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST);
|
||||
*buf = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST);
|
||||
return 1;
|
||||
});
|
||||
|
||||
@@ -486,7 +487,21 @@ void P2PServer::load_peer_list()
|
||||
// Load peers from seed nodes if we're on the default or mini sidechain
|
||||
auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) {
|
||||
for (size_t i = 0; nodes[i][0]; ++i) {
|
||||
LOGINFO(4, "loading peers from " << nodes[i]);
|
||||
const char* cur_node = nodes[i];
|
||||
LOGINFO(4, "loading peers from " << cur_node);
|
||||
|
||||
// Prefer DNS TXT records
|
||||
const bool has_txt = get_dns_txt_records(cur_node, [&saved_list, cur_node](const char* s, size_t n) {
|
||||
if (!saved_list.empty()) {
|
||||
saved_list += ',';
|
||||
}
|
||||
LOGINFO(4, "added " << log::const_buf(s, n) << " from " << cur_node);
|
||||
saved_list.append(s, n);
|
||||
});
|
||||
|
||||
if (has_txt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addrinfo hints{};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
@@ -494,11 +509,11 @@ void P2PServer::load_peer_list()
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
|
||||
addrinfo* result;
|
||||
int err = getaddrinfo(nodes[i], nullptr, &hints, &result);
|
||||
int err = getaddrinfo(cur_node, nullptr, &hints, &result);
|
||||
if (err) {
|
||||
LOGWARN(4, "getaddrinfo failed for " << nodes[i] << ": " << gai_strerror(err) << ", retrying with IPv4 only");
|
||||
LOGWARN(4, "getaddrinfo failed for " << cur_node << ": " << gai_strerror(err) << ", retrying with IPv4 only");
|
||||
hints.ai_family = AF_INET;
|
||||
err = getaddrinfo(nodes[i], nullptr, &hints, &result);
|
||||
err = getaddrinfo(cur_node, nullptr, &hints, &result);
|
||||
}
|
||||
if (err == 0) {
|
||||
for (addrinfo* r = result; r != NULL; r = r->ai_next) {
|
||||
@@ -524,7 +539,7 @@ void P2PServer::load_peer_list()
|
||||
}
|
||||
|
||||
if (s.m_pos) {
|
||||
LOGINFO(4, "added " << static_cast<const char*>(buf) << " from " << nodes[i]);
|
||||
LOGINFO(4, "added " << static_cast<const char*>(buf) << " from " << cur_node);
|
||||
if (!saved_list.empty()) {
|
||||
saved_list += ',';
|
||||
}
|
||||
@@ -534,7 +549,7 @@ void P2PServer::load_peer_list()
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
else {
|
||||
LOGWARN(3, "getaddrinfo failed for " << nodes[i] << ": " << gai_strerror(err));
|
||||
LOGWARN(3, "getaddrinfo failed for " << cur_node << ": " << gai_strerror(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -601,10 +616,10 @@ void P2PServer::load_peer_list()
|
||||
|
||||
void P2PServer::load_monerod_peer_list()
|
||||
{
|
||||
const Params& params = m_pool->params();
|
||||
const Params::Host& host = m_pool->current_host();
|
||||
|
||||
JSONRPCRequest::call(params.m_host, params.m_rpcPort, "/get_peer_list", params.m_rpcLogin, m_socks5Proxy,
|
||||
[this](const char* data, size_t size)
|
||||
JSONRPCRequest::call(host.m_address, host.m_rpcPort, "/get_peer_list", host.m_rpcLogin, m_socks5Proxy,
|
||||
[this](const char* data, size_t size, double)
|
||||
{
|
||||
#define ERR_STR "/get_peer_list RPC request returned invalid JSON "
|
||||
|
||||
@@ -671,7 +686,7 @@ void P2PServer::load_monerod_peer_list()
|
||||
|
||||
LOGINFO(4, "monerod peer list loaded (" << m_peerListMonero.size() << " peers)");
|
||||
},
|
||||
[](const char* data, size_t size)
|
||||
[](const char* data, size_t size, double)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGWARN(4, "/get_peer_list RPC request failed: error " << log::const_buf(data, size));
|
||||
@@ -699,7 +714,7 @@ void P2PServer::update_peer_in_list(bool is_v6, const raw_ip& ip, int port)
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::remove_peer_from_list(P2PClient* client)
|
||||
void P2PServer::remove_peer_from_list(const P2PClient* client)
|
||||
{
|
||||
MutexLock lock(m_peerListLock);
|
||||
|
||||
@@ -864,10 +879,9 @@ void P2PServer::on_broadcast()
|
||||
}
|
||||
|
||||
for (Broadcast* data : broadcast_queue) {
|
||||
const bool result = send(client, [client, data](void* buf, size_t buf_size) -> size_t
|
||||
const bool result = send(client, [client, data](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
bool send_pruned = true;
|
||||
bool send_compact = (client->m_protocolVersion >= PROTOCOL_VERSION_1_1) && !data->compact_blob.empty() && (data->compact_blob.size() < data->pruned_blob.size());
|
||||
@@ -921,7 +935,7 @@ void P2PServer::on_broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
if (!result) {
|
||||
LOGWARN(5, "failed to broadcast to " << static_cast<char*>(client->m_addrString) << ", disconnecting");
|
||||
@@ -1016,6 +1030,10 @@ int P2PServer::deserialize_block(const uint8_t* buf, uint32_t size, bool compact
|
||||
|
||||
void P2PServer::on_timer()
|
||||
{
|
||||
if (m_pool->stopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
++m_timerCounter;
|
||||
|
||||
if (!m_initialPeerList.empty()) {
|
||||
@@ -1028,7 +1046,7 @@ void P2PServer::on_timer()
|
||||
update_peer_list();
|
||||
save_peer_list_async();
|
||||
update_peer_connections();
|
||||
check_zmq();
|
||||
check_host();
|
||||
check_block_template();
|
||||
api_update_local_stats();
|
||||
}
|
||||
@@ -1124,7 +1142,7 @@ void P2PServer::download_missing_blocks()
|
||||
}
|
||||
|
||||
const bool result = send(client,
|
||||
[&id, client](void* buf, size_t buf_size) -> size_t
|
||||
[&id, client](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id << " to " << static_cast<char*>(client->m_addrString));
|
||||
|
||||
@@ -1132,15 +1150,14 @@ void P2PServer::download_missing_blocks()
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
@@ -1149,25 +1166,41 @@ void P2PServer::download_missing_blocks()
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::check_zmq()
|
||||
void P2PServer::check_host()
|
||||
{
|
||||
if ((m_timerCounter % 30) != 3) {
|
||||
if (!m_pool->startup_finished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_pool->zmq_running()) {
|
||||
LOGERR(1, "ZMQ is not running, restarting it");
|
||||
m_pool->restart_zmq();
|
||||
m_pool->reconnect_to_host();
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t height = m_pool->miner_data().height;
|
||||
const SideChain& side_chain = m_pool->side_chain();
|
||||
|
||||
// If the latest 5 side chain blocks are 2 or more Monero blocks ahead, then the node is probably stuck
|
||||
uint32_t counter = 5;
|
||||
for (const PoolBlock* b = side_chain.chainTip(); b && (b->m_txinGenHeight >= height + 2); b = side_chain.find_block(b->m_parent)) {
|
||||
if (--counter == 0) {
|
||||
const Params::Host& host = m_pool->current_host();
|
||||
LOGERR(1, host.m_displayName << " seems to be stuck, reconnecting");
|
||||
m_pool->reconnect_to_host();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const uint64_t last_active = m_pool->zmq_last_active();
|
||||
|
||||
// If there were no ZMQ messages in the last 5 minutes, then the node is probably stuck
|
||||
if (cur_time >= last_active + 300) {
|
||||
const uint64_t dt = static_cast<uint64_t>(cur_time - last_active);
|
||||
LOGERR(1, "no ZMQ messages received from monerod in the last " << dt << " seconds, check your monerod/p2pool/network/firewall setup!!!");
|
||||
m_pool->restart_zmq();
|
||||
const Params::Host& host = m_pool->current_host();
|
||||
LOGERR(1, "no ZMQ messages received from " << host.m_displayName << " in the last " << dt << " seconds, check your monerod/p2pool/network/firewall setup!!!");
|
||||
m_pool->reconnect_to_host();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1195,8 +1228,7 @@ P2PServer::P2PClient::P2PClient()
|
||||
, m_handshakeComplete(false)
|
||||
, m_handshakeInvalid(false)
|
||||
, m_listenPort(-1)
|
||||
, m_fastPeerListRequestCount(0)
|
||||
, m_prevIncomingPeerListRequest(0)
|
||||
, m_prevPeersSent(0)
|
||||
, m_nextOutgoingPeerListRequest(0)
|
||||
, m_lastPeerListRequestTime{}
|
||||
, m_peerListPendingRequests(0)
|
||||
@@ -1214,6 +1246,8 @@ P2PServer::P2PClient::P2PClient()
|
||||
|
||||
void P2PServer::on_shutdown()
|
||||
{
|
||||
save_peer_list();
|
||||
|
||||
uv_timer_stop(&m_timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_timer), nullptr);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(&m_broadcastAsync), nullptr);
|
||||
@@ -1295,8 +1329,7 @@ void P2PServer::P2PClient::reset()
|
||||
m_handshakeComplete = false;
|
||||
m_handshakeInvalid = false;
|
||||
m_listenPort = -1;
|
||||
m_fastPeerListRequestCount = 0;
|
||||
m_prevIncomingPeerListRequest = 0;
|
||||
m_prevPeersSent = 0;
|
||||
m_nextOutgoingPeerListRequest = 0;
|
||||
m_lastPeerListRequestTime = {};
|
||||
m_peerListPendingRequests = 0;
|
||||
@@ -1604,7 +1637,7 @@ bool P2PServer::P2PClient::send_handshake_challenge()
|
||||
m_handshakeChallenge = owner->get_random64();
|
||||
|
||||
return owner->send(this,
|
||||
[this, owner](void* buf, size_t buf_size) -> size_t
|
||||
[this, owner](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending HANDSHAKE_CHALLENGE to " << static_cast<char*>(m_addrString));
|
||||
|
||||
@@ -1612,8 +1645,7 @@ bool P2PServer::P2PClient::send_handshake_challenge()
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE);
|
||||
|
||||
@@ -1627,7 +1659,7 @@ bool P2PServer::P2PClient::send_handshake_challenge()
|
||||
memcpy(p, &k, sizeof(uint64_t));
|
||||
p += sizeof(uint64_t);
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1700,7 +1732,7 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t* value = reinterpret_cast<uint64_t*>(work->solution.h);
|
||||
const uint64_t* value = reinterpret_cast<uint64_t*>(work->solution.h);
|
||||
|
||||
uint64_t high;
|
||||
umul128(value[HASH_SIZE / sizeof(uint64_t) - 1], CHALLENGE_DIFFICULTY, &high);
|
||||
@@ -1728,7 +1760,7 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
|
||||
}
|
||||
|
||||
const bool result = work->server->send(work->client,
|
||||
[work](void* buf, size_t buf_size) -> size_t
|
||||
[work](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending HANDSHAKE_SOLUTION to " << static_cast<char*>(work->client->m_addrString));
|
||||
|
||||
@@ -1736,8 +1768,7 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION);
|
||||
|
||||
@@ -1751,7 +1782,7 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
|
||||
work->client->on_after_handshake(p);
|
||||
}
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
@@ -1847,7 +1878,7 @@ bool P2PServer::P2PClient::on_handshake_solution(const uint8_t* buf)
|
||||
|
||||
// Check that incoming connection provided enough PoW
|
||||
if (m_isIncoming) {
|
||||
uint64_t* value = reinterpret_cast<uint64_t*>(solution.h);
|
||||
const uint64_t* value = reinterpret_cast<uint64_t*>(solution.h);
|
||||
|
||||
uint64_t high;
|
||||
umul128(value[HASH_SIZE / sizeof(uint64_t) - 1], CHALLENGE_DIFFICULTY, &high);
|
||||
@@ -1875,7 +1906,7 @@ bool P2PServer::P2PClient::on_handshake_solution(const uint8_t* buf)
|
||||
}
|
||||
|
||||
return m_owner->send(this,
|
||||
[this](void* buf, size_t buf_size) -> size_t
|
||||
[this](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending LISTEN_PORT and BLOCK_REQUEST for the chain tip to " << static_cast<char*>(m_addrString));
|
||||
|
||||
@@ -1883,10 +1914,9 @@ bool P2PServer::P2PClient::on_handshake_solution(const uint8_t* buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
on_after_handshake(p);
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1905,11 +1935,11 @@ void P2PServer::P2PClient::on_after_handshake(uint8_t* &p)
|
||||
LOGINFO(5, "sending BLOCK_REQUEST for the chain tip to " << static_cast<char*>(m_addrString));
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
hash empty;
|
||||
memcpy(p, empty.h, HASH_SIZE);
|
||||
hash zero_hash;
|
||||
memcpy(p, zero_hash.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
|
||||
m_blockPendingRequests.push_back(empty);
|
||||
m_blockPendingRequests.push_back(zero_hash);
|
||||
m_lastBroadcastTimestamp = seconds_since_epoch();
|
||||
}
|
||||
|
||||
@@ -1944,7 +1974,7 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
|
||||
}
|
||||
|
||||
return server->send(this,
|
||||
[this, &blob](void* buf, size_t buf_size) -> size_t
|
||||
[this, &blob](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending BLOCK_RESPONSE to " << static_cast<char*>(m_addrString));
|
||||
|
||||
@@ -1954,8 +1984,7 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_RESPONSE);
|
||||
|
||||
@@ -1967,21 +1996,25 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
}
|
||||
|
||||
bool P2PServer::P2PClient::on_block_response(const uint8_t* buf, uint32_t size, const hash& expected_id)
|
||||
{
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
|
||||
if (!size) {
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(m_addrString) << log::NoColor() << " sent an empty block response");
|
||||
if (expected_id.empty() && (cur_time >= m_nextOutgoingPeerListRequest)) {
|
||||
server->send_peer_list_request(this, cur_time);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t received_timestamp = microseconds_since_epoch();
|
||||
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
|
||||
MutexLock lock(server->m_blockLock);
|
||||
|
||||
const int result = server->deserialize_block(buf, size, false, received_timestamp);
|
||||
@@ -2002,7 +2035,6 @@ bool P2PServer::P2PClient::on_block_response(const uint8_t* buf, uint32_t size,
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
if (cur_time >= m_nextOutgoingPeerListRequest) {
|
||||
server->send_peer_list_request(this, cur_time);
|
||||
}
|
||||
@@ -2085,46 +2117,40 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
server->check_event_loop_thread(__func__);
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const bool first = (m_prevIncomingPeerListRequest == 0);
|
||||
|
||||
// Allow peer list requests no more than once every 30 seconds
|
||||
if (cur_time - m_prevIncomingPeerListRequest < 30) {
|
||||
++m_fastPeerListRequestCount;
|
||||
if (m_fastPeerListRequestCount >= 3) {
|
||||
LOGWARN(4, "peer " << static_cast<char*>(m_addrString) << " is sending PEER_LIST_REQUEST too often");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_prevIncomingPeerListRequest = cur_time;
|
||||
|
||||
Peer peers[PEER_LIST_RESPONSE_MAX_PEERS];
|
||||
uint32_t num_selected_peers = 0;
|
||||
|
||||
// Send every 4th peer on average, selected at random
|
||||
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
||||
uint32_t n = 0;
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const bool first = (m_prevPeersSent == 0);
|
||||
|
||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if (!client->is_good() || (client->m_addr == m_addr)) {
|
||||
continue;
|
||||
}
|
||||
// Rate limit peer list requests (send an empty response if the request comes too soon)
|
||||
if (first || (cur_time >= m_prevPeersSent + PEER_REQUEST_DELAY)) {
|
||||
m_prevPeersSent = cur_time;
|
||||
|
||||
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
||||
++n;
|
||||
// Send every 4th peer on average, selected at random
|
||||
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
||||
uint32_t n = 0;
|
||||
|
||||
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
||||
if (num_selected_peers < peers_to_send_target) {
|
||||
peers[num_selected_peers++] = p;
|
||||
continue;
|
||||
}
|
||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if (!client->is_good() || (client->m_addr == m_addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t k;
|
||||
umul128(server->get_random64(), n, &k);
|
||||
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
||||
++n;
|
||||
|
||||
if (k < peers_to_send_target) {
|
||||
peers[k] = p;
|
||||
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
||||
if (num_selected_peers < peers_to_send_target) {
|
||||
peers[num_selected_peers++] = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t k;
|
||||
umul128(server->get_random64(), n, &k);
|
||||
|
||||
if (k < peers_to_send_target) {
|
||||
peers[k] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2150,7 +2176,7 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
}
|
||||
|
||||
return server->send(this,
|
||||
[this, &peers, num_selected_peers](void* buf, size_t buf_size) -> size_t
|
||||
[this, &peers, num_selected_peers](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(6, "sending PEER_LIST_RESPONSE to " << static_cast<char*>(m_addrString));
|
||||
|
||||
@@ -2158,8 +2184,7 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE);
|
||||
*(p++) = static_cast<uint8_t>(num_selected_peers);
|
||||
@@ -2176,7 +2201,7 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
p += 2;
|
||||
}
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2200,6 +2225,7 @@ void P2PServer::P2PClient::on_peer_list_response(const uint8_t* buf)
|
||||
buf += 2;
|
||||
|
||||
// Treat IPv4-mapped addresses as regular IPv4 addresses
|
||||
// cppcheck-suppress uninitvar
|
||||
if (is_v6 && ip.is_ipv4_prefix()) {
|
||||
is_v6 = false;
|
||||
}
|
||||
@@ -2294,7 +2320,7 @@ bool P2PServer::P2PClient::handle_incoming_block_async(const PoolBlock* block, u
|
||||
}
|
||||
}
|
||||
|
||||
if (side_chain.block_seen(*block)) {
|
||||
if (side_chain.incoming_block_seen(*block)) {
|
||||
LOGINFO(6, "block " << block->m_sidechainId << " (nonce " << block->m_nonce << ", extra_nonce " << block->m_extraNonce << ") was received before, skipping it");
|
||||
return true;
|
||||
}
|
||||
@@ -2391,7 +2417,7 @@ void P2PServer::P2PClient::post_handle_incoming_block(const uint32_t reset_count
|
||||
}
|
||||
|
||||
const bool result = server->send(this,
|
||||
[this, &id](void* buf, size_t buf_size) -> size_t
|
||||
[this, &id](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id << " to " << static_cast<char*>(m_addrString));
|
||||
|
||||
@@ -2399,15 +2425,14 @@ void P2PServer::P2PClient::post_handle_incoming_block(const uint32_t reset_count
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
|
||||
uint8_t* p = p0;
|
||||
uint8_t* p = buf;
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
|
||||
return p - p0;
|
||||
return p - buf;
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
|
||||
+3
-4
@@ -131,8 +131,7 @@ 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;
|
||||
@@ -191,7 +190,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();
|
||||
@@ -201,7 +200,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;
|
||||
|
||||
+159
-85
@@ -69,36 +69,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 +118,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 +186,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 +201,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 +319,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 +341,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 +393,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 +461,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 +551,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 +626,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 +673,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 +739,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 +762,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 +776,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 +789,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 +823,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 +849,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 +902,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.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();
|
||||
}
|
||||
}
|
||||
@@ -917,7 +967,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 +1018,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 +1044,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 +1088,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.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 +1134,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 +1184,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 +1226,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;
|
||||
}
|
||||
@@ -1562,33 +1618,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,7 +1683,11 @@ 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();
|
||||
|
||||
+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;
|
||||
|
||||
+7
-1
@@ -137,8 +137,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;
|
||||
|
||||
|
||||
+81
-5
@@ -20,6 +20,8 @@
|
||||
#include "stratum_server.h"
|
||||
#include "p2p_server.h"
|
||||
|
||||
constexpr char log_category_prefix[] = "P2Pool ";
|
||||
|
||||
void p2pool_usage();
|
||||
|
||||
namespace p2pool {
|
||||
@@ -30,17 +32,35 @@ Params::Params(int argc, char* const argv[])
|
||||
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* const 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* const 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* const 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
|
||||
|
||||
+26
-4
@@ -27,9 +27,32 @@ struct Params
|
||||
|
||||
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;
|
||||
|
||||
+4
-3
@@ -447,9 +447,10 @@ bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t h
|
||||
volatile 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 +460,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));
|
||||
|
||||
+72
-30
@@ -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);
|
||||
@@ -206,7 +209,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) {
|
||||
@@ -466,7 +469,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;
|
||||
@@ -476,15 +479,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)
|
||||
@@ -542,14 +565,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;
|
||||
}
|
||||
|
||||
@@ -579,13 +602,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;
|
||||
@@ -604,12 +635,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);
|
||||
@@ -912,7 +946,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) {
|
||||
@@ -988,7 +1022,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())) <<
|
||||
@@ -1722,6 +1756,7 @@ void SideChain::update_chain_tip(const PoolBlock* block)
|
||||
}
|
||||
}
|
||||
prune_old_blocks();
|
||||
cleanup_incoming_blocks();
|
||||
}
|
||||
}
|
||||
else if (block->m_sidechainHeight > tip->m_sidechainHeight) {
|
||||
@@ -1994,7 +2029,6 @@ void SideChain::prune_old_blocks()
|
||||
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;
|
||||
}
|
||||
@@ -2025,6 +2059,28 @@ void SideChain::prune_old_blocks()
|
||||
|
||||
// Pre-calc workers are not needed anymore
|
||||
finish_precalc();
|
||||
|
||||
#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) {
|
||||
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->print_hosts();
|
||||
m_pool->stop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2275,20 +2331,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
|
||||
|
||||
+11
-4
@@ -46,8 +46,10 @@ 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;
|
||||
@@ -116,8 +118,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 +155,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);
|
||||
|
||||
@@ -287,7 +287,7 @@ 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();
|
||||
@@ -377,7 +377,7 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
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";
|
||||
@@ -463,7 +463,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";
|
||||
@@ -773,7 +773,7 @@ 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));
|
||||
|
||||
@@ -985,7 +985,7 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
|
||||
if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) {
|
||||
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) {
|
||||
|
||||
+25
-21
@@ -27,6 +27,7 @@ TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_
|
||||
: m_allocateNewClient(allocate_new_client)
|
||||
, m_defaultBacklog(default_backlog)
|
||||
, m_loopThread{}
|
||||
, m_loopThreadRunning(false)
|
||||
#ifdef WITH_UPNP
|
||||
, m_portMapping(0)
|
||||
#endif
|
||||
@@ -112,7 +113,7 @@ void TCPServer::parse_address_list_internal(const std::string& address_list, Cal
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -473,7 +474,9 @@ void TCPServer::shutdown_tcp()
|
||||
}
|
||||
#endif
|
||||
|
||||
uv_thread_join(&m_loopThread);
|
||||
if (m_loopThreadRunning.load()) {
|
||||
uv_thread_join(&m_loopThread);
|
||||
}
|
||||
|
||||
uv_mutex_destroy(&m_bansLock);
|
||||
|
||||
@@ -573,6 +576,9 @@ bool TCPServer::send_internal(Client* client, Callback<size_t, uint8_t*, size_t>
|
||||
void TCPServer::loop(void* data)
|
||||
{
|
||||
TCPServer* server = static_cast<TCPServer*>(data);
|
||||
server->m_loopThreadRunning.exchange(true);
|
||||
ON_SCOPE_LEAVE([server]() { server->m_loopThreadRunning.exchange(false); });
|
||||
|
||||
log_category_prefix = server->get_category();
|
||||
|
||||
LOGINFO(1, "event loop started");
|
||||
@@ -803,16 +809,15 @@ void TCPServer::on_new_client(uv_stream_t* server, Client* client)
|
||||
}
|
||||
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;
|
||||
});
|
||||
@@ -1076,27 +1081,26 @@ bool TCPServer::Client::on_proxy_handshake(char* data, uint32_t size)
|
||||
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 + 12, 4);
|
||||
buf[8] = static_cast<uint8_t>(m_port >> 8);
|
||||
buf[9] = static_cast<uint8_t>(m_port & 0xFF);
|
||||
}
|
||||
|
||||
return m_isV6 ? 22 : 10;
|
||||
@@ -1113,7 +1117,7 @@ bool TCPServer::Client::on_proxy_handshake(char* data, uint32_t size)
|
||||
|
||||
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;
|
||||
|
||||
@@ -149,6 +149,7 @@ protected:
|
||||
int m_defaultBacklog;
|
||||
|
||||
uv_thread_t m_loopThread;
|
||||
std::atomic<bool> m_loopThreadRunning;
|
||||
|
||||
static void loop(void* data);
|
||||
|
||||
|
||||
+91
-7
@@ -31,6 +31,15 @@
|
||||
#include "upnpcommands.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
static constexpr char log_category_prefix[] = "Util ";
|
||||
|
||||
namespace p2pool {
|
||||
@@ -45,6 +54,11 @@ const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MIN
|
||||
#endif
|
||||
" on " __DATE__ ")";
|
||||
|
||||
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)
|
||||
@@ -462,6 +476,71 @@ 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
|
||||
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];
|
||||
const size_t n = strlen(s);
|
||||
if (n > 0) {
|
||||
callback(s, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DnsRecordListFree(pQueryResults, DnsFreeRecordList);
|
||||
|
||||
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
|
||||
@@ -647,23 +726,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,8 +779,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);
|
||||
}
|
||||
|
||||
+6
-1
@@ -35,7 +35,7 @@
|
||||
namespace p2pool {
|
||||
|
||||
#define P2POOL_VERSION_MAJOR 3
|
||||
#define P2POOL_VERSION_MINOR 3
|
||||
#define P2POOL_VERSION_MINOR 5
|
||||
|
||||
extern const char* VERSION;
|
||||
|
||||
@@ -296,6 +296,11 @@ struct Callback
|
||||
};
|
||||
};
|
||||
|
||||
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))); }
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
void memory_tracking_start();
|
||||
|
||||
+92
-38
@@ -25,7 +25,7 @@ static constexpr char log_category_prefix[] = "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,14 +38,16 @@ 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) {
|
||||
@@ -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;
|
||||
|
||||
@@ -95,7 +95,7 @@ include_directories(src)
|
||||
include_directories(googletest/googletest/include)
|
||||
|
||||
if (WIN32)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi wldap32)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi dnsapi dbghelp)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(LIBS ${LIBS} bcrypt)
|
||||
endif()
|
||||
@@ -107,17 +107,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)
|
||||
@@ -174,6 +174,8 @@ 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}>)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Binary file not shown.
@@ -160,7 +160,7 @@ TEST(pool_block, verify)
|
||||
ASSERT_EQ(b.deserialize(p, n, sidechain, nullptr, false), 0);
|
||||
p += n;
|
||||
|
||||
sidechain.add_block(b);
|
||||
ASSERT_TRUE(sidechain.add_block(b));
|
||||
ASSERT_TRUE(sidechain.find_block(b.m_sidechainId) != nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
|
||||
f = open('stratum_dummy' + sys.argv[1] + '.log', 'wb');
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(1)
|
||||
sock.setblocking(True)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
while sock.connect_ex(('127.0.0.1', 3333)) != 0:
|
||||
f.write(b'.\n')
|
||||
print('.')
|
||||
time.sleep(1)
|
||||
|
||||
diff = '';
|
||||
|
||||
if (sys.argv[1] == '2'):
|
||||
diff = '+1000';
|
||||
if (sys.argv[1] == '3'):
|
||||
diff = '+10000000';
|
||||
|
||||
request = '{"id":1,"method":"login","params":{"login":"x' + diff + '"}}\n'
|
||||
sock.sendall(request.encode('utf-8'))
|
||||
|
||||
while True:
|
||||
data = sock.recv(1024)
|
||||
if len(data) == 0:
|
||||
break;
|
||||
f.write(data)
|
||||
f.flush()
|
||||
print(data.decode('utf-8'))
|
||||
|
||||
sock.close()
|
||||
f.close()
|
||||
@@ -0,0 +1,4 @@
|
||||
race:p2pool::log::Worker::run()
|
||||
race:p2pool::log::Worker::write
|
||||
called_from_lib:libzmq.so
|
||||
race_top:do_loglevel
|
||||
@@ -0,0 +1 @@
|
||||
shift-base:crypto-ops.c
|
||||
@@ -87,6 +87,10 @@ TEST(util, bsr)
|
||||
for (uint64_t i = 0, x = 1; i <= 63; ++i, x <<= 1) {
|
||||
ASSERT_EQ(bsr(x), i);
|
||||
ASSERT_EQ(bsr_reference(x), i);
|
||||
|
||||
const uint64_t y = x | (x - 1);
|
||||
ASSERT_EQ(bsr(y), i);
|
||||
ASSERT_EQ(bsr_reference(y), i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user