diff options
83 files changed, 1284 insertions, 542 deletions
diff --git a/.github/actions/set-make-job-count/action.yml b/.github/actions/set-make-job-count/action.yml new file mode 100644 index 000000000..68779ef3f --- /dev/null +++ b/.github/actions/set-make-job-count/action.yml @@ -0,0 +1,22 @@ +name: 'set-make-job-count' +description: 'Set the MAKE_JOB_COUNT environment variable to a value suitable for the host runner' +runs: + using: "composite" + steps: + # Each job runner requires 2.25 GiB (i.e. 1024 * 9/4 MiB) memory and + # a dedicated logical CPU core + - name: set-jobs-macOS + if: runner.os == 'macOS' + run: | + echo MAKE_JOB_COUNT=$(expr $(printf '%s\n%s' $(( $(sysctl -n hw.memsize) * 4 / (1073741824 * 9) )) $(sysctl -n hw.logicalcpu) | sort -n | head -n1) '|' 1) >> $GITHUB_ENV + shell: bash + - name: set-jobs-windows + if: runner.os == 'Windows' + run: | + echo MAKE_JOB_COUNT=$(expr $(printf '%s\n%s' $(( $(grep MemTotal: /proc/meminfo | cut -d: -f2 | cut -dk -f1) * 4 / (1048576 * 9) )) $(nproc) | sort -n | head -n1) '|' 1) >> $GITHUB_ENV + shell: msys2 {0} + - name: set-jobs-linux + if: runner.os == 'Linux' + run: | + echo MAKE_JOB_COUNT=$(expr $(printf '%s\n%s' $(( $(grep MemTotal: /proc/meminfo | cut -d: -f2 | cut -dk -f1) * 4 / (1048576 * 9) )) $(nproc) | sort -n | head -n1) '|' 1) >> $GITHUB_ENV + shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c1e381c0..29926e23d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,6 +2,9 @@ name: ci/gh-actions/cli on: push: + paths-ignore: + - 'docs/**' + - '**/README.md' pull_request: paths-ignore: - 'docs/**' @@ -9,40 +12,46 @@ on: # The below variables reduce repetitions across similar targets env: - REMOVE_BUNDLED_BOOST : rm -rf /usr/local/share/boost - BUILD_DEFAULT_LINUX: | - cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Release && cmake --build build -j3 - APT_INSTALL_LINUX: 'sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler ccache' + # ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere. + BUILD_DEFAULT_LINUX: 'cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Release && cmake --build build --target all && cmake --build build --target wallet_api' + APT_INSTALL_LINUX: 'apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler ccache git' APT_SET_CONF: | - echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom - echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom - echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom + tee -a /etc/apt/apt.conf.d/80-custom << EOF + Acquire::Retries "3"; + Acquire::http::Timeout "120"; + Acquire::ftp::Timeout "120"; + EOF CCACHE_SETTINGS: | - ccache --max-size=150M - ccache --set-config=compression=true + ccache --max-size=150M + ccache --set-config=compression=true jobs: build-macos: + name: 'macOS (brew)' runs-on: macOS-latest env: CCACHE_TEMPDIR: /tmp/.ccache-temp steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - uses: actions/cache@v3 - with: - path: /Users/runner/Library/Caches/ccache - key: ccache-${{ runner.os }}-build-${{ github.sha }} - restore-keys: ccache-${{ runner.os }}-build- - - name: install dependencies - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf ccache - - name: build - run: | - ${{env.CCACHE_SETTINGS}} - make -j3 + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/cache@v4 + with: + path: /Users/runner/Library/Caches/ccache + key: ccache-${{ runner.os }}-build-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}-build- + - uses: ./.github/actions/set-make-job-count + - name: install dependencies + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install boost@1.85 hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf ccache + brew link boost@1.85 + - name: build + run: | + ${{env.CCACHE_SETTINGS}} + make -j${{env.MAKE_JOB_COUNT}} build-windows: + name: 'Windows (MSYS2)' runs-on: windows-latest env: CCACHE_TEMPDIR: C:\Users\runneradmin\.ccache-temp @@ -51,134 +60,184 @@ jobs: run: shell: msys2 {0} steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - uses: actions/cache@v3 - with: - path: C:\Users\runneradmin\.ccache - key: ccache-${{ runner.os }}-build-${{ github.sha }} - restore-keys: ccache-${{ runner.os }}-build- - - uses: msys2/setup-msys2@v2 - with: - update: true - install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git - - name: build - run: | - ${{env.CCACHE_SETTINGS}} - make release-static-win64 -j2 + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/cache@v4 + with: + path: C:\Users\runneradmin\.ccache + key: ccache-${{ runner.os }}-build-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}-build- + - uses: msys2/setup-msys2@v2 + with: + update: true + install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git + - shell: msys2 {0} + run: | + curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-boost-1.86.0-7-any.pkg.tar.zst + echo "3e84674b4d2b3ab82f4d5e22bcc2015fa139b6fd936c55d6b71f89a72a1ee0a2 mingw-w64-x86_64-boost-1.86.0-7-any.pkg.tar.zst" | sha256sum -c + curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-boost-libs-1.86.0-7-any.pkg.tar.zst + echo "4cb1d1066fffa6a5788b212ccb920c6d8cc93a8ecbbc633565bfc9b2ebc6feb5 mingw-w64-x86_64-boost-libs-1.86.0-7-any.pkg.tar.zst" | sha256sum -c + curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-icu-75.1-2-any.pkg.tar.zst + echo "bf57882d43efcdfd746463613ea982c69b64aa4ba9bed4cb24c02a81ad06c3a9 mingw-w64-x86_64-icu-75.1-2-any.pkg.tar.zst" | sha256sum -c + pacman --noconfirm -U mingw-w64-x86_64-boost-1.86.0-7-any.pkg.tar.zst mingw-w64-x86_64-boost-libs-1.86.0-7-any.pkg.tar.zst mingw-w64-x86_64-icu-75.1-2-any.pkg.tar.zst + - uses: ./.github/actions/set-make-job-count + - name: build + run: | + ${{env.CCACHE_SETTINGS}} + make release-static-win64 -j${{env.MAKE_JOB_COUNT}} -# See the OS labels and monitor deprecations here: -# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources + build-debian: + # Oldest supported Debian version + name: 'Debian 10' + runs-on: ubuntu-latest + container: + image: debian:10 + env: + DEBIAN_FRONTEND: noninteractive + steps: + - name: set apt conf + run: ${{env.APT_SET_CONF}} + - name: update apt + run: apt update + - name: install monero dependencies + run: ${{env.APT_INSTALL_LINUX}} + - name: configure git + run: git config --global --add safe.directory '*' + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: ./.github/actions/set-make-job-count + - name: build + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{env.MAKE_JOB_COUNT}} + run: ${{env.BUILD_DEFAULT_LINUX}} build-ubuntu: - runs-on: ${{ matrix.os }} - env: - CCACHE_TEMPDIR: /tmp/.ccache-temp + name: ${{ matrix.name }} + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-20.04] - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - uses: actions/cache@v3 - with: - path: ~/.ccache - key: ccache-${{ runner.os }}-build-${{ matrix.os }}-${{ github.sha }} - restore-keys: ccache-${{ runner.os }}-build-${{ matrix.os }} - - name: remove bundled boost - run: ${{env.REMOVE_BUNDLED_BOOST}} - - name: set apt conf - run: ${{env.APT_SET_CONF}} - - name: update apt - run: sudo apt update - - name: install monero dependencies - run: ${{env.APT_INSTALL_LINUX}} - - name: build - run: | - ${{env.CCACHE_SETTINGS}} - ${{env.BUILD_DEFAULT_LINUX}} + include: + # Oldest supported Ubuntu LTS version + - name: Ubuntu 20.04 + container: ubuntu:20.04 - libwallet-ubuntu: - runs-on: ubuntu-20.04 - env: - CCACHE_TEMPDIR: /tmp/.ccache-temp + # Most popular Ubuntu LTS version + - name: Ubuntu 22.04 + container: ubuntu:22.04 + container: + image: ${{ matrix.container }} + env: + DEBIAN_FRONTEND: noninteractive + CCACHE_TEMPDIR: /tmp/.ccache-temp + CCACHE_DIR: ~/.ccache steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - uses: actions/cache@v3 - with: - path: ~/.ccache - key: ccache-${{ runner.os }}-libwallet-${{ github.sha }} - restore-keys: ccache-${{ runner.os }}-libwallet- - - name: remove bundled boost - run: ${{env.REMOVE_BUNDLED_BOOST}} - - name: set apt conf - run: ${{env.APT_SET_CONF}} - - name: update apt - run: sudo apt update - - name: install monero dependencies - run: ${{env.APT_INSTALL_LINUX}} - - name: build - run: | - ${{env.CCACHE_SETTINGS}} - cmake . - make wallet_api -j3 + - name: set apt conf + run: ${{env.APT_SET_CONF}} + - name: update apt + run: apt update + - name: install monero dependencies + run: ${{env.APT_INSTALL_LINUX}} + - name: configure git + run: git config --global --add safe.directory '*' + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/cache@v4 + with: + path: ~/.ccache + key: ccache-${{ matrix.container }}-build-${{ github.sha }} + restore-keys: ccache-${{ matrix.container }}-build- + - uses: ./.github/actions/set-make-job-count + - name: build + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{env.MAKE_JOB_COUNT}} + run: | + ${{env.CCACHE_SETTINGS}} + ${{env.BUILD_DEFAULT_LINUX}} test-ubuntu: + name: "${{ matrix.name }} (tests)" needs: build-ubuntu - runs-on: ubuntu-20.04 - env: - CCACHE_TEMPDIR: /tmp/.ccache-temp - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - name: ccache - uses: actions/cache@v3 - with: - path: ~/.ccache - key: ccache-${{ runner.os }}-build-ubuntu-latest-${{ github.sha }} - restore-keys: ccache-${{ runner.os }}-build-ubuntu-latest - - name: remove bundled boost - run: ${{env.REMOVE_BUNDLED_BOOST}} - - name: set apt conf - run: ${{env.APT_SET_CONF}} - - name: update apt - run: sudo apt update - - name: install monero dependencies - run: ${{env.APT_INSTALL_LINUX}} - - name: install Python dependencies - run: pip install requests psutil monotonic zmq deepdiff - - name: tests + runs-on: ubuntu-latest + strategy: + matrix: + include: + - name: Ubuntu 20.04 + container: ubuntu:20.04 + container: + image: ${{ matrix.container }} env: - CTEST_OUTPUT_ON_FAILURE: ON - DNS_PUBLIC: tcp://9.9.9.9 - run: | - ${{env.CCACHE_SETTINGS}} - ${{env.BUILD_DEFAULT_LINUX}} - cmake --build build --target test - -# ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere. -# BUILD_SHARED_LIBS=ON speeds up the linkage part a bit, reduces size, and is the only place where the dynamic linkage is tested. + DEBIAN_FRONTEND: noninteractive + CCACHE_TEMPDIR: /tmp/.ccache-temp + CCACHE_DIR: ~/.ccache + # Setting up a loop device (losetup) requires additional capabilities. + # tests/create_test_disks.sh + options: --privileged + steps: + - name: set apt conf + run: ${{env.APT_SET_CONF}} + - name: update apt + run: apt update + - name: install monero dependencies + run: ${{env.APT_INSTALL_LINUX}} + - name: install pip + run: apt install -y python3-pip + - name: install Python dependencies + run: pip install requests psutil monotonic zmq deepdiff + - name: configure git + run: git config --global --add safe.directory '*' + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/cache@v4 + with: + path: ~/.ccache + key: ccache-${{ matrix.container }}-build-${{ github.sha }} + restore-keys: ccache-${{ matrix.container }}-build- + - name: create dummy disk drives for testing + run: tests/create_test_disks.sh >> $GITHUB_ENV + - uses: ./.github/actions/set-make-job-count + - name: tests + env: + CTEST_OUTPUT_ON_FAILURE: ON + DNS_PUBLIC: tcp://9.9.9.9 + CMAKE_BUILD_PARALLEL_LEVEL: ${{env.MAKE_JOB_COUNT}} + run: | + ${{env.CCACHE_SETTINGS}} + ${{env.BUILD_DEFAULT_LINUX}} + cmake --build build --target test source-archive: - runs-on: ubuntu-20.04 + name: "source archive" + runs-on: ubuntu-latest + container: + image: ubuntu:20.04 + env: + DEBIAN_FRONTEND: noninteractive steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - submodules: recursive - - name: archive - run: | - pip install git-archive-all - export VERSION="monero-$(git describe)" - export OUTPUT="$VERSION.tar" - echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV - /home/runner/.local/bin/git-archive-all --prefix "$VERSION/" --force-submodules "$OUTPUT" - - uses: actions/upload-artifact@v3 - with: - name: ${{ env.OUTPUT }} - path: /home/runner/work/monero/monero/${{ env.OUTPUT }} + - name: set apt conf + run: ${{env.APT_SET_CONF}} + - name: update apt + run: apt update + - name: install dependencies + run: apt install -y git python3-pip + - name: configure git + run: git config --global --add safe.directory '*' + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + - name: archive + run: | + pip install git-archive-all + export VERSION="monero-$(git describe)" + export OUTPUT="$VERSION.tar" + echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV + git-archive-all --prefix "$VERSION/" --force-submodules "$OUTPUT" + - uses: actions/upload-artifact@v4 + with: + name: ${{ env.OUTPUT }} + path: ${{ env.OUTPUT }} diff --git a/.github/workflows/depends.yml b/.github/workflows/depends.yml index 710a548a5..c754260b2 100644 --- a/.github/workflows/depends.yml +++ b/.github/workflows/depends.yml @@ -9,18 +9,23 @@ on: env: APT_SET_CONF: | - echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom - echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom - echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom + tee -a /etc/apt/apt.conf.d/80-custom << EOF + Acquire::Retries "3"; + Acquire::http::Timeout "120"; + Acquire::ftp::Timeout "120"; + EOF CCACHE_SETTINGS: | ccache --max-size=150M ccache --set-config=compression=true jobs: build-cross: - runs-on: ubuntu-20.04 - env: - CCACHE_TEMPDIR: /tmp/.ccache-temp + runs-on: ubuntu-latest + container: + image: ubuntu:20.04 + env: + DEBIAN_FRONTEND: noninteractive + CCACHE_TEMPDIR: /tmp/.ccache-temp strategy: fail-fast: false matrix: @@ -48,29 +53,35 @@ jobs: packages: "gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev" - name: "Cross-Mac x86_64" host: "x86_64-apple-darwin11" - packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" + packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git libtinfo5" - name: "Cross-Mac aarch64" host: "aarch64-apple-darwin11" - packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" + packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git libtinfo5" - name: "x86_64 Freebsd" host: "x86_64-unknown-freebsd" packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev" name: ${{ matrix.toolchain.name }} steps: - - uses: actions/checkout@v3 + - name: set apt conf + run: ${{env.APT_SET_CONF}} + - name: install dependencies + run: apt update; apt -y install build-essential libtool cmake autotools-dev automake pkg-config python3 gperf bsdmainutils curl git ca-certificates unzip ccache ${{ matrix.toolchain.packages }} + - name: configure git + run: git config --global --add safe.directory '*' + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: recursive # Most volatile cache - name: ccache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.ccache key: ccache-${{ matrix.toolchain.host }}-${{ github.sha }} restore-keys: ccache-${{ matrix.toolchain.host }}- # Less volatile cache - name: depends cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: contrib/depends/built key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }} @@ -79,28 +90,24 @@ jobs: depends-${{ matrix.toolchain.host }}- # Static cache - name: OSX SDK cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: contrib/depends/sdk-sources key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }} restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }} - - name: set apt conf - run: ${{env.APT_SET_CONF}} - - name: install dependencies - run: sudo apt update; sudo apt -y install build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache ${{ matrix.toolchain.packages }} - name: prepare w64-mingw32 if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'i686-w64-mingw32' }} run: | - sudo update-alternatives --set ${{ matrix.toolchain.host }}-g++ $(which ${{ matrix.toolchain.host }}-g++-posix) - sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix) + update-alternatives --set ${{ matrix.toolchain.host }}-g++ $(which ${{ matrix.toolchain.host }}-g++-posix) + update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix) - name: build run: | ${{env.CCACHE_SETTINGS}} - make depends target=${{ matrix.toolchain.host }} -j2 - - uses: actions/upload-artifact@v3 + make depends target=${{ matrix.toolchain.host }} -j4 + - uses: actions/upload-artifact@v4 if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }} with: name: ${{ matrix.toolchain.name }} path: | - /home/runner/work/monero/monero/build/${{ matrix.toolchain.host }}/release/bin/monero-wallet-cli* - /home/runner/work/monero/monero/build/${{ matrix.toolchain.host }}/release/bin/monerod* + build/${{ matrix.toolchain.host }}/release/bin/monero-wallet-cli* + build/${{ matrix.toolchain.host }}/release/bin/monerod* diff --git a/.github/workflows/gitian.yml b/.github/workflows/gitian.yml index 91e60a88f..db9735ac3 100644 --- a/.github/workflows/gitian.yml +++ b/.github/workflows/gitian.yml @@ -42,7 +42,7 @@ jobs: echo \`\`\` >> $GITHUB_STEP_SUMMARY shasum -a256 * >> $GITHUB_STEP_SUMMARY echo \`\`\` >> $GITHUB_STEP_SUMMARY - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ matrix.operating-system.name }} path: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fb03ba1f..db69b1b04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1075,25 +1075,43 @@ if(STATIC) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) endif() -find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options locale) -add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) -set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES}) +# Find Boost headers +set(BOOST_MIN_VER 1.62) +find_package(Boost ${BOOST_MIN_VER} QUIET REQUIRED) + if(NOT Boost_FOUND) - die("Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (>=1.58) or the equivalent") + die("Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (>=${BOOST_MIN_VER}) or the equivalent") elseif(Boost_FOUND) - message(STATUS "Found Boost Version: ${Boost_VERSION}") - if (Boost_VERSION VERSION_LESS 10 AND Boost_VERSION VERSION_LESS 1.62.0 AND NOT (OPENSSL_VERSION VERSION_LESS 1.1)) - set(BOOST_BEFORE_1_62 true) - endif() - if (NOT Boost_VERSION VERSION_LESS 10 AND Boost_VERSION VERSION_LESS 106200 AND NOT (OPENSSL_VERSION VERSION_LESS 1.1)) - set(BOOST_BEFORE_1_62 true) + message(STATUS "Found Boost Version: ${Boost_VERSION_STRING}") + + set(BOOST_COMPONENTS filesystem thread date_time chrono serialization program_options locale) + + # Boost System is header-only since 1.69 + if (Boost_VERSION_STRING VERSION_LESS 1.69.0) + list(APPEND BOOST_COMPONENTS system) endif() - if (BOOST_BEFORE_1_62) - message(FATAL_ERROR "Boost ${Boost_VERSION} (older than 1.62) is too old to link with OpenSSL ${OPENSSL_VERSION} (1.1 or newer) found at ${OPENSSL_INCLUDE_DIR} and ${OPENSSL_LIBRARIES}. " - "Update Boost or install OpenSSL 1.0 and set path to it when running cmake: " - "cmake -DOPENSSL_ROOT_DIR='/usr/include/openssl-1.0'") + + # Boost Regex is header-only since 1.77 + if (Boost_VERSION_STRING VERSION_LESS 1.77.0) + list(APPEND BOOST_COMPONENTS regex) endif() + + message(STATUS "Boost components: ${BOOST_COMPONENTS}") + + # Find required Boost libraries + find_package(Boost ${BOOST_MIN_VER} QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES}) +endif() + +add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) +add_definitions(-DBOOST_NO_AUTO_PTR) +add_definitions(-DBOOST_UUID_DISABLE_ALIGNMENT) # This restores UUID's std::has_unique_object_representations property + +if(FREEBSD AND DEPENDS) + # Boost 1.66.0 fails to detect that we have <string_view>, resulting in an incorrect include. + # This line can be removed if Boost is upgraded to > 1.66.0. + add_definitions(-DBOOST_ASIO_HAS_STD_STRING_VIEW) endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) @@ -1188,6 +1206,7 @@ endif() if(NOT ZMQ_LIB) message(FATAL_ERROR "Could not find required libzmq") endif() +include_directories(${ZMQ_INCLUDE_PATH}) if(PGM_LIBRARY) set(ZMQ_LIB "${ZMQ_LIB};${PGM_LIBRARY}") endif() @@ -1201,7 +1220,15 @@ if(PROTOLIB_LIBRARY) set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}") endif() if(SODIUM_LIBRARY) + message(STATUS "ZMQ_LIB: ${ZMQ_LIB};${SODIUM_LIBRARY}") set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}") + find_path(SODIUM_INCLUDE_PATH sodium/crypto_verify_32.h) + if (SODIUM_INCLUDE_PATH) + message(STATUS "SODIUM_INCLUDE_PATH: ${SODIUM_INCLUDE_PATH}") + include_directories(${SODIUM_INCLUDE_PATH}) + else() + message(FATAL_ERROR "Could not find required sodium/crypto_verify_32.h") + endif() endif() if(BSD_LIBRARY) set(ZMQ_LIB "${ZMQ_LIB};${BSD_LIBRARY}") @@ -138,8 +138,8 @@ Dates are provided in the format YYYY-MM-DD. | 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs | 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format | 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format -| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.3.3 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm -| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.3.3 | forbid old v14 transaction format +| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.3.4 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm +| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.3.4 | forbid old v14 transaction format | XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX | X's indicate that these details have not been determined as of commit date. @@ -168,7 +168,7 @@ library archives (`.a`). | GCC | 5 | NO | `build-essential` | `base-devel` | `base-devel` | `gcc` | NO | | | CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | `cmake` | NO | | | pkg-config | any | NO | `pkg-config` | `base-devel` | `base-devel` | `pkgconf` | NO | | -| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | `boost-devel` | NO | C++ libraries | +| Boost | 1.62 | NO | `libboost-all-dev` | `boost` | `boost-devel` | `boost-devel` | NO | C++ libraries | | OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `libressl-devel` | `openssl-devel` | NO | sha256 sum | | libzmq | 4.2.0 | NO | `libzmq3-dev` | `zeromq` | `zeromq-devel` | `zeromq-devel` | NO | ZeroMQ library | | OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | | `openpgm-devel` | NO | For ZeroMQ | @@ -344,7 +344,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/monero-project/monero.git cd monero - git checkout v0.18.3.3 + git checkout v0.18.3.4 ``` * Build: @@ -463,10 +463,10 @@ application. cd monero ``` -* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.3.3'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.3.4'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.18.3.3 + git checkout v0.18.3.4 ``` * If you are on a 64-bit system, run: diff --git a/contrib/brew/Brewfile b/contrib/brew/Brewfile index c74e7b2a2..a159345cf 100644 --- a/contrib/brew/Brewfile +++ b/contrib/brew/Brewfile @@ -16,7 +16,7 @@ brew "binutils" brew "coreutils" brew "cmake" brew "pkg-config" -brew "boost" +brew "boost@1.85", link: true brew "openssl" brew "hidapi" brew "zmq" diff --git a/contrib/depends/packages/boost.mk b/contrib/depends/packages/boost.mk index fd06c5393..402fc84a5 100644 --- a/contrib/depends/packages/boost.mk +++ b/contrib/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_64_0 -$(package)_download_path=https://downloads.sourceforge.net/project/boost/boost/1.64.0/ -$(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 +$(package)_version=1.66.0 +$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/ +$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz +$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60 $(package)_dependencies=libiconv $(package)_patches=fix_aroptions.patch fix_arm_arch.patch @@ -25,7 +25,7 @@ $(package)_archiver_darwin=$($(package)_libtool) $(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale $(package)_cxxflags=-std=c++11 $(package)_cxxflags_linux=-fPIC -$(package)_cxxflags_freebsd=-fPIC +$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1 endef define $(package)_preprocess_cmds diff --git a/contrib/epee/include/byte_stream.h b/contrib/epee/include/byte_stream.h index e7993133a..ec9e5cbca 100644 --- a/contrib/epee/include/byte_stream.h +++ b/contrib/epee/include/byte_stream.h @@ -74,6 +74,7 @@ namespace epee public: using char_type = std::uint8_t; using Ch = char_type; + using value_type = char_type; //! Increase internal buffer by at least `byte_stream_increase` bytes. byte_stream() noexcept @@ -86,6 +87,7 @@ namespace epee ~byte_stream() noexcept = default; byte_stream& operator=(byte_stream&& rhs) noexcept; + std::uint8_t* data() noexcept { return buffer_.get(); } const std::uint8_t* data() const noexcept { return buffer_.get(); } std::uint8_t* tellp() const noexcept { return next_write_; } std::size_t available() const noexcept { return end_ - next_write_; } diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h index de95e58c3..107bf535a 100644 --- a/contrib/epee/include/file_io_utils.h +++ b/contrib/epee/include/file_io_utils.h @@ -38,7 +38,6 @@ namespace file_io_utils bool is_file_exist(const std::string& path); bool save_string_to_file(const std::string& path_to_file, const std::string& str); bool load_file_to_string(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000); - bool get_file_size(const std::string& path_to_file, uint64_t &size); } } diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index bc0da66e2..be9999203 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -76,6 +76,13 @@ namespace net_utils protected: virtual ~i_connection_filter(){} }; + + struct i_connection_limit + { + virtual bool is_host_limit(const epee::net_utils::network_address &address)=0; + protected: + virtual ~i_connection_limit(){} + }; /************************************************************************/ @@ -260,10 +267,11 @@ namespace net_utils struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type { shared_state() - : connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), stop_signal_sent(false) + : connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), plimit(nullptr), stop_signal_sent(false) {} i_connection_filter* pfilter; + i_connection_limit* plimit; bool stop_signal_sent; }; @@ -369,6 +377,7 @@ namespace net_utils size_t get_threads_count(){return m_threads_count;} void set_connection_filter(i_connection_filter* pfilter); + void set_connection_limit(i_connection_limit* plimit); void set_default_remote(epee::net_utils::network_address remote) { diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index d88f18194..8a3a8299c 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -328,7 +328,7 @@ namespace net_utils return; } auto self = connection<T>::shared_from_this(); - if (m_connection_type != e_connection_type_RPC) { + if (speed_limit_is_enabled()) { auto calc_duration = []{ CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_in @@ -382,7 +382,7 @@ namespace net_utils m_conn_context.m_max_speed_down, speed ); - { + if (speed_limit_is_enabled()) { CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_in ); @@ -454,7 +454,7 @@ namespace net_utils return; } auto self = connection<T>::shared_from_this(); - if (m_connection_type != e_connection_type_RPC) { + if (speed_limit_is_enabled()) { auto calc_duration = [this]{ CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_out @@ -513,7 +513,7 @@ namespace net_utils m_conn_context.m_max_speed_down, speed ); - { + if (speed_limit_is_enabled()) { CRITICAL_REGION_LOCAL( network_throttle_manager_t::m_lock_get_global_throttle_out ); @@ -873,6 +873,13 @@ namespace net_utils ).pfilter; if (filter && !filter->is_remote_host_allowed(*real_remote)) return false; + + auto *limit = static_cast<shared_state&>( + connection_basic::get_state() + ).plimit; + if (limit && limit->is_host_limit(*real_remote)) + return false; + ec_t ec; #if !defined(_WIN32) || !defined(__i686) connection_basic::socket_.next_layer().set_option( @@ -1022,7 +1029,7 @@ namespace net_utils template<typename T> bool connection<T>::speed_limit_is_enabled() const { - return m_connection_type != e_connection_type_RPC; + return m_connection_type == e_connection_type_P2P; } template<typename T> @@ -1349,6 +1356,13 @@ namespace net_utils } //--------------------------------------------------------------------------------- template<class t_protocol_handler> + void boosted_tcp_server<t_protocol_handler>::set_connection_limit(i_connection_limit* plimit) + { + assert(m_state != nullptr); // always set in constructor + m_state->plimit = plimit; + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs) { TRY_ENTRY(); diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index ffb3f3b7e..8d68f041b 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -171,6 +171,13 @@ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \ return true; \ } \ + epee::serialization::storage_entry params_; \ + params_ = epee::serialization::storage_entry(epee::serialization::section()); \ + if(!ps.get_value("params", params_, nullptr)) \ + { \ + epee::serialization::section params_section; \ + ps.set_value("params", std::move(params_section), nullptr); \ + } \ if(false) return true; //just a stub to have "else if" diff --git a/contrib/epee/include/net/network_throttle-detail.hpp b/contrib/epee/include/net/network_throttle-detail.hpp index 0a6dc4a20..3a88105c7 100644 --- a/contrib/epee/include/net/network_throttle-detail.hpp +++ b/contrib/epee/include/net/network_throttle-detail.hpp @@ -46,13 +46,13 @@ namespace net_utils class network_throttle : public i_network_throttle { - private: + public: struct packet_info { size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second) packet_info(); }; - + private: network_speed_bps m_target_speed; size_t m_network_add_cost; // estimated add cost of headers size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h index 06d74329f..fbbddc7d2 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -98,16 +98,18 @@ public: \ #define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \ epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name); -#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \ - static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \ - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) +#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(variable, val_name) \ + static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \ + static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \ + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name) -#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \ +#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(variable, val_name, default_value) \ do { \ - static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \ - bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \ + static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \ + static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \ + bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name) \ if (!ret) \ - epee::serialize_default(this_ref.varialble, default_value); \ + epee::serialize_default(this_ref.variable, default_value); \ } while(0); #define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \ @@ -118,7 +120,7 @@ public: \ #define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble) #define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble) #define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(varialble, def) KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, #varialble, def) -#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check +#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_trivially_copyable and is_standard_layout compile time check #define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble) #define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value) diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h index 23bd51f8c..01dc387d6 100644 --- a/contrib/epee/include/span.h +++ b/contrib/epee/include/span.h @@ -133,17 +133,14 @@ namespace epee return {src.data(), src.size()}; } - template<typename T> - constexpr bool has_padding() noexcept - { - return !std::is_standard_layout<T>() || alignof(T) != 1; - } - //! \return Cast data from `src` as `span<const std::uint8_t>`. template<typename T> span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept { - static_assert(!has_padding<T>(), "source type may have padding"); + static_assert(!std::is_empty<T>(), "empty value types will not work -> sizeof == 1"); + static_assert(std::is_standard_layout<T>(), "type must have standard layout"); + static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable"); + static_assert(alignof(T) == 1, "type may have padding"); return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()}; } @@ -153,7 +150,9 @@ namespace epee { using value_type = typename T::value_type; static_assert(!std::is_empty<value_type>(), "empty value types will not work -> sizeof == 1"); - static_assert(!has_padding<value_type>(), "source value type may have padding"); + static_assert(std::is_standard_layout<value_type>(), "value type must have standard layout"); + static_assert(std::is_trivially_copyable<value_type>(), "value type must be trivially copyable"); + static_assert(alignof(value_type) == 1, "value type may have padding"); return {reinterpret_cast<std::uint8_t*>(src.data()), src.size() * sizeof(value_type)}; } @@ -162,7 +161,9 @@ namespace epee span<const std::uint8_t> as_byte_span(const T& src) noexcept { static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1"); - static_assert(!has_padding<T>(), "source type may have padding"); + static_assert(std::is_standard_layout<T>(), "type must have standard layout"); + static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable"); + static_assert(alignof(T) == 1, "type may have padding"); return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)}; } @@ -171,7 +172,9 @@ namespace epee span<std::uint8_t> as_mut_byte_span(T& src) noexcept { static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1"); - static_assert(!has_padding<T>(), "source type may have padding"); + static_assert(std::is_standard_layout<T>(), "type must have standard layout"); + static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable"); + static_assert(alignof(T) == 1, "type may have padding"); return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)}; } diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h index 96b0c024c..5eb9acffd 100644 --- a/contrib/epee/include/storages/portable_storage_val_converters.h +++ b/contrib/epee/include/storages/portable_storage_val_converters.h @@ -37,6 +37,7 @@ #include "misc_log_ex.h" #include <boost/lexical_cast.hpp> +#include <boost/numeric/conversion/bounds.hpp> #include <typeinfo> #include <iomanip> diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 31c55b97b..8b26f49ae 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -71,8 +71,6 @@ namespace string_tools std::string get_current_module_path(); #endif void set_module_name_and_folder(const std::string& path_to_process_); - void trim_left(std::string& str); - void trim_right(std::string& str); //---------------------------------------------------------------------------- inline std::string& trim(std::string& str) { @@ -91,6 +89,7 @@ namespace string_tools std::string pod_to_hex(const t_pod_type& s) { static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type"); + static_assert(alignof(t_pod_type) == 1, "type may have padding"); return to_hex::string(as_byte_span(s)); } //---------------------------------------------------------------------------- @@ -98,6 +97,8 @@ namespace string_tools bool hex_to_pod(const boost::string_ref hex_str, t_pod_type& s) { static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type"); + static_assert(alignof(t_pod_type) == 1, "type may have padding"); + static_assert(std::is_trivially_copyable<t_pod_type>(), "type must be trivially copyable"); return from_hex::to_buffer(as_mut_byte_span(s), hex_str); } //---------------------------------------------------------------------------- diff --git a/contrib/epee/src/byte_slice.cpp b/contrib/epee/src/byte_slice.cpp index 72aa39768..47d440dff 100644 --- a/contrib/epee/src/byte_slice.cpp +++ b/contrib/epee/src/byte_slice.cpp @@ -152,7 +152,11 @@ namespace epee { std::size_t space_needed = 0; for (const auto& source : sources) + { + if (std::numeric_limits<std::size_t>::max() - space_needed < source.size()) + throw std::bad_alloc{}; space_needed += source.size(); + } if (space_needed) { @@ -162,9 +166,9 @@ namespace epee for (const auto& source : sources) { + assert(source.size() <= out.size()); // see check above std::memcpy(out.data(), source.data(), source.size()); - if (out.remove_prefix(source.size()) < source.size()) - throw std::bad_alloc{}; // size_t overflow on space_needed + out.remove_prefix(source.size()); } storage_ = std::move(storage); } diff --git a/contrib/epee/src/file_io_utils.cpp b/contrib/epee/src/file_io_utils.cpp index c0798a510..bc592cb9f 100644 --- a/contrib/epee/src/file_io_utils.cpp +++ b/contrib/epee/src/file_io_utils.cpp @@ -149,40 +149,5 @@ namespace file_io_utils } #endif } - - - bool get_file_size(const std::string& path_to_file, uint64_t &size) - { -#ifdef _WIN32 - std::wstring wide_path; - try { wide_path = string_tools::utf8_to_utf16(path_to_file); } catch (...) { return false; } - HANDLE file_handle = CreateFileW(wide_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file_handle == INVALID_HANDLE_VALUE) - return false; - LARGE_INTEGER file_size; - BOOL result = GetFileSizeEx(file_handle, &file_size); - CloseHandle(file_handle); - if (result) { - size = file_size.QuadPart; - } - return size; -#else - try - { - std::ifstream fstream; - fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); - fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate); - size = fstream.tellg(); - fstream.close(); - return true; - } - - catch(...) - { - return false; - } -#endif - } - } } diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index 4ca1a3632..46b535504 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -176,11 +176,12 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s std::vector<boost::filesystem::path> found_files; const boost::filesystem::directory_iterator end_itr; const boost::filesystem::path filename_base_path(filename_base); + const std::string filename_base_name = filename_base_path.filename().string(); const boost::filesystem::path parent_path = filename_base_path.has_parent_path() ? filename_base_path.parent_path() : "."; for (boost::filesystem::directory_iterator iter(parent_path); iter != end_itr; ++iter) { - const std::string filename = iter->path().string(); - if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0) + const std::string filename = iter->path().filename().string(); + if (filename.size() >= filename_base_name.size() && std::memcmp(filename.data(), filename_base_name.data(), filename_base_name.size()) == 0) { found_files.push_back(iter->path()); } diff --git a/contrib/epee/src/network_throttle-detail.cpp b/contrib/epee/src/network_throttle-detail.cpp index 978572120..1e554c500 100644 --- a/contrib/epee/src/network_throttle-detail.cpp +++ b/contrib/epee/src/network_throttle-detail.cpp @@ -46,7 +46,7 @@ #include "misc_log_ex.h" #include <boost/chrono.hpp> #include "misc_language.h" -#include <sstream> +#include <fstream> #include <iomanip> #include <algorithm> @@ -186,6 +186,23 @@ void network_throttle::handle_trafic_exact(size_t packet_size) _handle_trafic_exact(packet_size, packet_size); } +namespace +{ + struct output_history + { + const boost::circular_buffer< network_throttle::packet_info >& history; + }; + + std::ostream& operator<<(std::ostream& out, const output_history& source) + { + out << '['; + for (auto sample: source.history) + out << sample.m_size << ' '; + out << ']'; + return out; + } +} + void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size) { tick(); @@ -196,14 +213,11 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s m_total_packets++; m_total_bytes += packet_size; - std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; - std::string history_str = oss.str(); - MTRACE("Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)" << " Speed AVG=" << std::setw(4) << ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]" << " " << std::setw(4) << ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]" <<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec " - << " " << history_str + << " " << output_history{m_history} ); } @@ -289,8 +303,6 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc } if (dbg) { - std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; - std::string history_str = oss.str(); MTRACE((cts.delay > 0 ? "SLEEP" : "") << "dbg " << m_name << ": " << "speed is A=" << std::setw(8) <<cts.average<<" vs " @@ -300,7 +312,7 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc << "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") " << "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " " << "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " " - << "History: " << std::setw(8) << history_str << " " + << "History: " << std::setw(8) << output_history{m_history} << " " << "m_last_sample_time=" << std::setw(8) << m_last_sample_time ); diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index cefde158c..ac68d1fdb 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -1,5 +1,4 @@ #include "readline_buffer.h" -#include "string_tools.h" #include <readline/readline.h> #include <readline/history.h> #include <iostream> @@ -174,7 +173,7 @@ static void handle_line(char* line) line_stat = rdln::full; the_line = line; std::string test_line = line; - epee::string_tools::trim_right(test_line); + boost::trim_right(test_line); if(!test_line.empty()) { if (!same_as_last_line(test_line)) diff --git a/contrib/epee/src/string_tools.cpp b/contrib/epee/src/string_tools.cpp index 4458dabdd..081cb9464 100644 --- a/contrib/epee/src/string_tools.cpp +++ b/contrib/epee/src/string_tools.cpp @@ -174,19 +174,6 @@ namespace string_tools } //---------------------------------------------------------------------------- - void trim_left(std::string& str) - { - boost::trim_left(str); - return; - } - - //---------------------------------------------------------------------------- - void trim_right(std::string& str) - { - boost::trim_right(str); - return; - } - std::string pad_string(std::string s, size_t n, char c, bool prepend) { if (s.size() < n) @@ -201,13 +188,18 @@ namespace string_tools std::string get_extension(const std::string& str) { - return boost::filesystem::path(str).extension().string(); + std::string ext_with_dot = boost::filesystem::path(str).extension().string(); + + if (ext_with_dot.empty()) + return {}; + + return ext_with_dot.erase(0, 1); } //---------------------------------------------------------------------------- std::string cut_off_extension(const std::string& str) { - return boost::filesystem::path(str).stem().string(); + return boost::filesystem::path(str).replace_extension("").string(); } #ifdef _WIN32 diff --git a/contrib/gitian/DOCKRUN.md b/contrib/gitian/DOCKRUN.md index 7994d39cc..189b543da 100644 --- a/contrib/gitian/DOCKRUN.md +++ b/contrib/gitian/DOCKRUN.md @@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the version to build as its only argument, e.g. ```bash -VERSION=v0.18.3.3 +VERSION=v0.18.3.4 ./dockrun.sh $VERSION ``` diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md index 6a97cbccb..ea3129f61 100644 --- a/contrib/gitian/README.md +++ b/contrib/gitian/README.md @@ -133,7 +133,7 @@ Common setup part: su - gitianuser GH_USER=YOUR_GITHUB_USER_NAME -VERSION=v0.18.3.3 +VERSION=v0.18.3.4 ``` Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build. diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 5b7f69a56..538e4d215 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -39,6 +39,7 @@ find_package(Miniupnpc REQUIRED) message(STATUS "Using in-tree miniupnpc") set(UPNPC_NO_INSTALL TRUE CACHE BOOL "Disable miniupnp installation" FORCE) +set(UPNPC_BUILD_SHARED OFF CACHE BOOL "Disable building shared library" FORCE) add_subdirectory(miniupnp/miniupnpc) set_property(TARGET libminiupnpc-static PROPERTY FOLDER "external") set_property(TARGET libminiupnpc-static PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index f80013d02..98d8c6e91 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -28,13 +28,17 @@ #include "db_lmdb.h" #include <boost/filesystem.hpp> +#include <boost/filesystem/fstream.hpp> #include <boost/format.hpp> #include <boost/circular_buffer.hpp> #include <memory> // std::unique_ptr #include <cstring> // memcpy +#ifdef WIN32 +#include <winioctl.h> +#endif + #include "string_tools.h" -#include "file_io_utils.h" #include "common/util.h" #include "common/pruning.h" #include "cryptonote_basic/cryptonote_format_utils.h" @@ -1321,6 +1325,54 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB() m_hardfork = nullptr; } +#ifdef WIN32 +static bool disable_ntfs_compression(const boost::filesystem::path& filepath) +{ + DWORD file_attributes = ::GetFileAttributesW(filepath.c_str()); + if (file_attributes == INVALID_FILE_ATTRIBUTES) + { + MERROR("Failed to get " << filepath.string() << " file attributes. Error: " << ::GetLastError()); + return false; + } + + if (!(file_attributes & FILE_ATTRIBUTE_COMPRESSED)) + return true; // not compressed + + LOG_PRINT_L1("Disabling NTFS compression for " << filepath.string()); + HANDLE file_handle = ::CreateFileW( + filepath.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + boost::filesystem::is_directory(filepath) ? FILE_FLAG_BACKUP_SEMANTICS : 0, // Needed to open handles to directories + nullptr + ); + + if (file_handle == INVALID_HANDLE_VALUE) + { + MERROR("Failed to open handle: " << filepath.string() << ". Error: " << ::GetLastError()); + return false; + } + + USHORT compression_state = COMPRESSION_FORMAT_NONE; + DWORD bytes_returned; + BOOL ok = ::DeviceIoControl( + file_handle, + FSCTL_SET_COMPRESSION, + &compression_state, + sizeof(compression_state), + nullptr, + 0, + &bytes_returned, + nullptr + ); + + ::CloseHandle(file_handle); + return ok; +} +#endif + void BlockchainLMDB::open(const std::string& filename, const int db_flags) { int result; @@ -1347,6 +1399,17 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) throw DB_ERROR("Database could not be opened"); } +#ifdef WIN32 + // ensure NTFS compression is disabled on the directory and database file to avoid corruption of the blockchain + if (!disable_ntfs_compression(filename)) + LOG_PRINT_L0("Failed to disable NTFS compression on folder: " << filename << ". Error: " << ::GetLastError()); + boost::filesystem::path datafile(filename); + datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME; + boost::filesystem::ofstream(datafile).close(); // touch the file to ensure it exists + if (!disable_ntfs_compression(datafile)) + throw DB_ERROR("Database file is NTFS compressend and compression could not be disabled"); +#endif + boost::optional<bool> is_hdd_result = tools::is_hdd(filename.c_str()); if (is_hdd_result) { @@ -4500,12 +4563,11 @@ bool BlockchainLMDB::is_read_only() const uint64_t BlockchainLMDB::get_database_size() const { - uint64_t size = 0; boost::filesystem::path datafile(m_folder); datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME; - if (!epee::file_io_utils::get_file_size(datafile.string(), size)) - size = 0; - return size; + boost::system::error_code ec{}; + const boost::uintmax_t size = boost::filesystem::file_size(datafile, ec); + return (ec ? 0 : static_cast<uint64_t>(size)); } void BlockchainLMDB::fixup() diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat Binary files differindex 2dc9ce3b3..2f1647ef5 100644 --- a/src/blocks/checkpoints.dat +++ b/src/blocks/checkpoints.dat diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 07f13656b..30d8266b7 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -250,6 +250,7 @@ namespace cryptonote ADD_CHECKPOINT2(2985000, "08f5e6b7301c1b6ed88268a28f8677a06e8ff943b3f9e48d3080f71f9c134bfb", "0x444b7b42a633c96"); ADD_CHECKPOINT2(3088000, "bddf8ca09110d33d6d497f13a113630c2b6af1c84d4f3a6f35cb1446f2604ade", "0x4aed3615c2f8c3e"); ADD_CHECKPOINT2(3102800, "083f4a34f9490403b564286e7f13fd1ed45c52c86fa47195f151594e5bc87504", "0x4bbed52d4da5dfb"); + ADD_CHECKPOINT2(3198000, "1d685b39be51e4e84e0af69fa78e023c7cb21de7d33acd012d0371d5f78712d5", "0x517d415fee3a816"); return true; } diff --git a/src/common/download.cpp b/src/common/download.cpp index 01d4a9aab..e377be266 100644 --- a/src/common/download.cpp +++ b/src/common/download.cpp @@ -30,7 +30,6 @@ #include <atomic> #include <boost/filesystem.hpp> #include <boost/thread/thread.hpp> -#include "file_io_utils.h" #include "net/http_client.h" #include "download.h" @@ -73,8 +72,11 @@ namespace tools { boost::unique_lock<boost::mutex> lock(control->mutex); std::ios_base::openmode mode = std::ios_base::out | std::ios_base::binary; - uint64_t existing_size = 0; - if (epee::file_io_utils::get_file_size(control->path, existing_size) && existing_size > 0) + boost::system::error_code ec{}; + uint64_t existing_size = static_cast<uint64_t>(boost::filesystem::file_size(control->path, ec)); + if (ec) + existing_size = 0; + if (existing_size > 0) { MINFO("Resuming downloading " << control->uri << " to " << control->path << " from " << existing_size); mode |= std::ios_base::app; diff --git a/src/common/password.cpp b/src/common/password.cpp index e6dff95ea..c0edf7a78 100644 --- a/src/common/password.cpp +++ b/src/common/password.cpp @@ -185,7 +185,7 @@ namespace return false; if (verify) { - std::cout << "Confirm password: "; + std::cout << "Confirm password: " << std::flush; if (!read_from_tty(pass2, hide_input)) return false; if(pass1!=pass2) diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index d8cd6c6a0..ee1cac04a 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -171,7 +171,9 @@ namespace crypto { /* Generate a value filled with random bytes. */ template<typename T> - typename std::enable_if<std::is_pod<T>::value, T>::type rand() { + T rand() { + static_assert(std::is_standard_layout<T>(), "cannot write random bytes into non-standard layout type"); + static_assert(std::is_trivially_copyable<T>(), "cannot write random bytes into non-trivially copyable type"); typename std::remove_cv<T>::type res; generate_random_bytes_thread_safe(sizeof(T), (uint8_t*)&res); return res; @@ -314,8 +316,14 @@ namespace crypto { inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; } - inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { - epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; + /* Do NOT overload the << operator for crypto::secret_key here. Use secret_key_explicit_print_ref + * instead to prevent accidental implicit dumping of secret key material to the logs (which has + * happened before). For the same reason, do not overload it for crypto::ec_scalar either since + * crypto::secret_key is a subclass. I'm not sorry that it's obtuse; that's the point, bozo. + */ + struct secret_key_explicit_print_ref { const crypto::secret_key &sk; }; + inline std::ostream &operator <<(std::ostream &o, const secret_key_explicit_print_ref v) { + epee::to_hex::formatted(o, epee::as_byte_span(unwrap(unwrap(v.sk)))); return o; } inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { epee::to_hex::formatted(o, epee::as_byte_span(v)); return o; diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h index 5a5e09f9b..3ff3619fe 100644 --- a/src/crypto/generic-ops.h +++ b/src/crypto/generic-ops.h @@ -33,6 +33,7 @@ #include <cstddef> #include <cstring> #include <functional> +#include <memory> #include <sodium/crypto_verify_32.h> #define CRYPTO_MAKE_COMPARABLE(type) \ @@ -60,14 +61,18 @@ namespace crypto { \ namespace crypto { \ static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \ inline std::size_t hash_value(const type &_v) { \ - return reinterpret_cast<const std::size_t &>(_v); \ + std::size_t h; \ + memcpy(&h, std::addressof(_v), sizeof(h)); \ + return h; \ } \ } \ namespace std { \ template<> \ struct hash<crypto::type> { \ std::size_t operator()(const crypto::type &_v) const { \ - return reinterpret_cast<const std::size_t &>(_v); \ + std::size_t h; \ + memcpy(&h, std::addressof(_v), sizeof(h)); \ + return h; \ } \ }; \ } diff --git a/src/cryptonote_basic/connection_context.cpp b/src/cryptonote_basic/connection_context.cpp index 4395bad9f..642749f3c 100644 --- a/src/cryptonote_basic/connection_context.cpp +++ b/src/cryptonote_basic/connection_context.cpp @@ -29,6 +29,7 @@ #include "connection_context.h" +#include <boost/optional/optional.hpp> #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "p2p/p2p_protocol_defs.h" @@ -69,4 +70,23 @@ namespace cryptonote }; return std::numeric_limits<size_t>::max(); } + + void cryptonote_connection_context::set_state_normal() + { + m_state = state_normal; + m_expected_heights_start = 0; + m_needed_objects.clear(); + m_needed_objects.shrink_to_fit(); + m_expected_heights.clear(); + m_expected_heights.shrink_to_fit(); + m_requested_objects.clear(); + } + + boost::optional<crypto::hash> cryptonote_connection_context::get_expected_hash(const uint64_t height) const + { + const auto difference = height - m_expected_heights_start; + if (height < m_expected_heights_start || m_expected_heights.size() < difference) + return boost::none; + return m_expected_heights[difference]; + } } // cryptonote diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h index 818999a60..db24e28fa 100644 --- a/src/cryptonote_basic/connection_context.h +++ b/src/cryptonote_basic/connection_context.h @@ -34,6 +34,7 @@ #include <atomic> #include <algorithm> #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/optional/optional_fwd.hpp> #include "net/net_utils_base.h" #include "crypto/hash.h" @@ -42,7 +43,7 @@ namespace cryptonote struct cryptonote_connection_context: public epee::net_utils::connection_context_base { cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0), - m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0), + m_expected_heights_start(0), m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0), m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0), m_expect_response(0), m_expect_height(0), m_num_requested(0) {} @@ -92,11 +93,18 @@ namespace cryptonote //! \return Maximum number of bytes permissible for `command`. static size_t get_max_bytes(int command) noexcept; + //! Use this instead of `m_state = state_normal`. + void set_state_normal(); + + boost::optional<crypto::hash> get_expected_hash(uint64_t height) const; + state m_state; std::vector<std::pair<crypto::hash, uint64_t>> m_needed_objects; + std::vector<crypto::hash> m_expected_heights; std::unordered_set<crypto::hash> m_requested_objects; uint64_t m_remote_blockchain_height; uint64_t m_last_response_height; + uint64_t m_expected_heights_start; boost::posix_time::ptime m_last_request_time; copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise crypto::hash m_last_known_hash; diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 8be23583b..e6e424c71 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -292,7 +292,7 @@ namespace cryptonote bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); if (!r) { - MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", <viewkey>)"); memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation)); } @@ -303,7 +303,7 @@ namespace cryptonote r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation); if (!r) { - MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")"); + MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", <viewkey>)"); } else { diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index f9e6a6cb9..d69556acd 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -145,8 +145,8 @@ #define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70 #define P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT 2 #define P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT 2 -#define P2P_DEFAULT_LIMIT_RATE_UP 2048 // kB/s -#define P2P_DEFAULT_LIMIT_RATE_DOWN 8192 // kB/s +#define P2P_DEFAULT_LIMIT_RATE_UP 8192 // kB/s +#define P2P_DEFAULT_LIMIT_RATE_DOWN 32768 // kB/s #define P2P_FAILED_ADDR_FORGET_SECONDS (60*60) //1 hour #define P2P_IP_BLOCKTIME (60*60*24) //24 hour diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 104c26977..fd56b07c6 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -851,20 +851,12 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph // less blocks than desired if there aren't enough. difficulty_type Blockchain::get_difficulty_for_next_block() { - LOG_PRINT_L3("Blockchain::" << __func__); - - std::stringstream ss; - bool print = false; - - int done = 0; - ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl; if (m_fixed_difficulty) { return m_db->height() ? m_fixed_difficulty : 1; } -start: - difficulty_type D = 0; + LOG_PRINT_L3("Blockchain::" << __func__); crypto::hash top_hash = get_tail_id(); { @@ -873,30 +865,21 @@ start: // something a bit out of date, but that's fine since anything which // requires the blockchain lock will have acquired it in the first place, // and it will be unlocked only when called from the getinfo RPC - ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl; if (top_hash == m_difficulty_for_next_block_top_hash) - { - ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl; - D = m_difficulty_for_next_block; - } + return m_difficulty_for_next_block; } CRITICAL_REGION_LOCAL(m_blockchain_lock); std::vector<uint64_t> timestamps; std::vector<difficulty_type> difficulties; uint64_t height; - auto new_top_hash = get_tail_id(height); // get it again now that we have the lock - ++height; - if (!(new_top_hash == top_hash)) D=0; - ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl; - top_hash = new_top_hash; - + top_hash = get_tail_id(height); // get it again now that we have the lock + ++height; // top block height to blockchain height // ND: Speedup // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty, // then when the next block difficulty is queried, push the latest height data and // pop the oldest one from the list. This only requires 1x read per height instead // of doing 735 (DIFFICULTY_BLOCKS_COUNT). - bool check = false; if (m_reset_timestamps_and_difficulties_height) m_timestamps_and_difficulties_height = 0; if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT) @@ -913,12 +896,8 @@ start: m_timestamps_and_difficulties_height = height; timestamps = m_timestamps; difficulties = m_difficulties; - check = true; } - //else - std::vector<uint64_t> timestamps_from_cache = timestamps; - std::vector<difficulty_type> difficulties_from_cache = difficulties; - + else { uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT)); if (offset == 0) @@ -931,68 +910,22 @@ start: timestamps.reserve(height - offset); difficulties.reserve(height - offset); } - ss << "Looking up " << (height - offset) << " from " << offset << std::endl; for (; offset < height; offset++) { timestamps.push_back(m_db->get_block_timestamp(offset)); difficulties.push_back(m_db->get_block_cumulative_difficulty(offset)); } - if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache) - { - ss << "Inconsistency XXX:" << std::endl; - ss << "top hash: "<<top_hash << std::endl; - ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl; - ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl; - ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << " " << v << std::endl; - ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << " " << v << std::endl; - ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << " " << v << std::endl; - ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << " " << v << std::endl; - - uint64_t dbh = m_db->height(); - uint64_t sh = dbh < 10000 ? 0 : dbh - 10000; - ss << "History from -10k at :" << dbh << ", from " << sh << std::endl; - for (uint64_t h = sh; h < dbh; ++h) - { - uint64_t ts = m_db->get_block_timestamp(h); - difficulty_type d = m_db->get_block_cumulative_difficulty(h); - ss << " " << h << " " << ts << " " << d << std::endl; - } - print = true; - } m_timestamps_and_difficulties_height = height; m_timestamps = timestamps; m_difficulties = difficulties; } - size_t target = get_difficulty_target(); difficulty_type diff = next_difficulty(timestamps, difficulties, target); CRITICAL_REGION_LOCAL1(m_difficulty_lock); m_difficulty_for_next_block_top_hash = top_hash; m_difficulty_for_next_block = diff; - if (D && D != diff) - { - ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl; - print = true; - } - - ++done; - if (done == 1 && D && D != diff) - { - print = true; - ss << "Might be a race. Let's see what happens if we try again..." << std::endl; - epee::misc_utils::sleep_no_w(100); - goto start; - } - ss << "Diff for " << top_hash << ": " << diff << std::endl; - if (print) - { - MGINFO("START DUMP"); - MGINFO(ss.str()); - MGINFO("END DUMP"); - MGINFO("Please send moneromooo on Libera.Chat the contents of this log, from a couple dozen lines before START DUMP to END DUMP"); - } return diff; } //------------------------------------------------------------------ @@ -1210,12 +1143,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info> // just the latter (because the rollback was done above). rollback_blockchain_switching(disconnected_chain, split_height); - // FIXME: Why do we keep invalid blocks around? Possibly in case we hear - // about them again so we can immediately dismiss them, but needs some - // looking into. const crypto::hash blkid = cryptonote::get_block_hash(bei.bl); - add_block_as_invalid(bei, blkid); - MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << blkid); m_db->remove_alt_block(blkid); alt_ch_iter++; @@ -1223,7 +1151,6 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info> { const auto &bei = *alt_ch_to_orph_iter++; const crypto::hash blkid = cryptonote::get_block_hash(bei.bl); - add_block_as_invalid(bei, blkid); m_db->remove_alt_block(blkid); } return false; @@ -2363,17 +2290,8 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const { // rct outputs don't exist before v4 - if (amount == 0) - { - switch (m_nettype) - { - case STAGENET: start_height = stagenet_hard_forks[3].height; break; - case TESTNET: start_height = testnet_hard_forks[3].height; break; - case MAINNET: start_height = mainnet_hard_forks[3].height; break; - case FAKECHAIN: start_height = 0; break; - default: return false; - } - } + if (amount == 0 && m_nettype != network_type::FAKECHAIN) + start_height = m_hardfork->get_earliest_ideal_height_for_version(HF_VERSION_DYNAMIC_FEE); else start_height = 0; base = 0; @@ -5552,7 +5470,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "0046a0019beb6e697e27d834d6127851425f7ee09bfb8e9f8df7b1420131aca8"; +static const char expected_block_hashes_hash[] = "8ada865350270fd008397684d978dac75ea4029a8a1ffcaa9975c43be119ec19"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index dc9d6612f..8f044154b 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -144,7 +144,7 @@ namespace cryptonote crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); - CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")"); + CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")"); r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")"); @@ -484,7 +484,7 @@ namespace cryptonote crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data()); ss_ring_s << "signatures:" << ENDL; std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;}); - ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL; + ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << crypto::secret_key_explicit_print_ref{in_contexts[i].in_ephemeral.sec} << ENDL << "real_output: " << src_entr.real_output << ENDL; i++; } diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp index 4e65eafa4..f8962df06 100644 --- a/src/cryptonote_protocol/block_queue.cpp +++ b/src/cryptonote_protocol/block_queue.cpp @@ -40,15 +40,6 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue" -namespace std { - static_assert(sizeof(size_t) <= sizeof(boost::uuids::uuid), "boost::uuids::uuid too small"); - template<> struct hash<boost::uuids::uuid> { - std::size_t operator()(const boost::uuids::uuid &_v) const { - return reinterpret_cast<const std::size_t &>(_v); - } - }; -} - namespace cryptonote { @@ -60,10 +51,10 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size)); if (has_hashes) { - for (const crypto::hash &h: hashes) + for (std::size_t i = 0; i < hashes.size(); ++i) { - requested_hashes.insert(h); - have_blocks.insert(h); + requested_hashes.insert(hashes[i]); + have_blocks.emplace(hashes[i], height + i); } set_span_hashes(height, connection_id, hashes); } @@ -228,6 +219,16 @@ bool block_queue::have(const crypto::hash &hash) const return have_blocks.find(hash) != have_blocks.end(); } +std::uint64_t block_queue::have_height(const crypto::hash &hash) const +{ + boost::unique_lock<boost::recursive_mutex> lock(mutex); + const auto elem = have_blocks.find(hash); + if (elem == have_blocks.end()) + return std::numeric_limits<std::uint64_t>::max(); + return elem->second; +} + + std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time) { boost::unique_lock<boost::recursive_mutex> lock(mutex); @@ -472,7 +473,7 @@ bool block_queue::has_spans(const boost::uuids::uuid &connection_id) const float block_queue::get_speed(const boost::uuids::uuid &connection_id) const { boost::unique_lock<boost::recursive_mutex> lock(mutex); - std::unordered_map<boost::uuids::uuid, float> speeds; + std::unordered_map<boost::uuids::uuid, float, boost::hash<boost::uuids::uuid>> speeds; for (const auto &span: blocks) { if (span.blocks.empty()) @@ -480,7 +481,7 @@ float block_queue::get_speed(const boost::uuids::uuid &connection_id) const // note that the average below does not average over the whole set, but over the // previous pseudo average and the latest rate: this gives much more importance // to the latest measurements, which is fine here - std::unordered_map<boost::uuids::uuid, float>::iterator i = speeds.find(span.connection_id); + const auto i = speeds.find(span.connection_id); if (i == speeds.end()) speeds.insert(std::make_pair(span.connection_id, span.rate)); else diff --git a/src/cryptonote_protocol/block_queue.h b/src/cryptonote_protocol/block_queue.h index 64ff106a3..df64948fa 100644 --- a/src/cryptonote_protocol/block_queue.h +++ b/src/cryptonote_protocol/block_queue.h @@ -98,6 +98,7 @@ namespace cryptonote bool foreach(std::function<bool(const span&)> f) const; bool requested(const crypto::hash &hash) const; bool have(const crypto::hash &hash) const; + std::uint64_t have_height(const crypto::hash &hash) const; private: void erase_block(block_map::iterator j); @@ -107,6 +108,6 @@ namespace cryptonote block_map blocks; mutable boost::recursive_mutex mutex; std::unordered_set<crypto::hash> requested_hashes; - std::unordered_set<crypto::hash> have_blocks; + std::unordered_map<crypto::hash, std::uint64_t> have_blocks; }; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 515b78c94..b003341e8 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -157,6 +157,7 @@ namespace cryptonote bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const; void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans); + void drop_connection(const boost::uuids::uuid&); void drop_connections(const epee::net_utils::network_address address); bool kick_idle_peers(); bool check_standby_peers(); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index ef437bdf6..ff9c7e5a1 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -35,6 +35,7 @@ // (may contain code and/or modifications by other developers) // developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting +#include <boost/optional/optional.hpp> #include <list> #include <ctime> @@ -380,7 +381,7 @@ namespace cryptonote if(m_core.have_block(hshd.top_id)) { - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); if(is_inital && hshd.current_height >= target && target == m_core.get_current_blockchain_height()) on_connection_synchronized(); return true; @@ -389,7 +390,7 @@ namespace cryptonote // No chain synchronization over hidden networks (tor, i2p, etc.) if(context.m_remote_address.get_zone() != epee::net_utils::zone::public_) { - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); return true; } @@ -430,7 +431,7 @@ namespace cryptonote if (m_no_sync) { - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); return true; } @@ -1198,8 +1199,9 @@ namespace cryptonote block_hashes.reserve(arg.blocks.size()); const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); uint64_t start_height = std::numeric_limits<uint64_t>::max(); + crypto::hash previous{}; cryptonote::block b; - for(const block_complete_entry& block_entry: arg.blocks) + for(std::size_t i = 0; i < arg.blocks.size(); ++i) { if (m_stopping) { @@ -1207,10 +1209,10 @@ namespace cryptonote } crypto::hash block_hash; - if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash)) + if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash)) { LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: " - << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection"); + << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection"); drop_connection(context, false, false); ++m_sync_bad_spans_downloaded; return 1; @@ -1218,14 +1220,25 @@ namespace cryptonote if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen)) { LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input" - << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection"); + << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection"); drop_connection(context, false, false); ++m_sync_bad_spans_downloaded; return 1; } + + const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height; + if (context.get_expected_hash(this_height) != block_hash) + { + LOG_ERROR_CCONTEXT("Sent invalid chain"); + drop_connection(context, false, false); + ++m_sync_bad_spans_downloaded; + return 1; + } + + // if first block if (start_height == std::numeric_limits<uint64_t>::max()) { - start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height; + start_height = this_height; if (start_height > context.m_expect_height) { LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection"); @@ -1233,21 +1246,45 @@ namespace cryptonote ++m_sync_bad_spans_downloaded; return 1; } + + if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id) + { + LOG_ERROR_CCONTEXT("Sent invalid chain"); + drop_connection(context, false, false); + ++m_sync_bad_spans_downloaded; + return 1; + } + } + else if (b.prev_id != previous) + { + LOG_ERROR_CCONTEXT("Sent invalid chain"); + drop_connection(context, false, false); + ++m_sync_bad_spans_downloaded; + return 1; + } + previous = block_hash; + + if (start_height + i != this_height) + { + LOG_ERROR_CCONTEXT("Sent invalid chain"); + drop_connection(context, false, false); + ++m_sync_bad_spans_downloaded; + return 1; } auto req_it = context.m_requested_objects.find(block_hash); if(req_it == context.m_requested_objects.end()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block)) << " wasn't requested, dropping connection"); drop_connection(context, false, false); ++m_sync_bad_spans_downloaded; return 1; } - if(b.tx_hashes.size() != block_entry.txs.size()) + if(b.tx_hashes.size() != arg.blocks[i].txs.size()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block)) - << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection"); + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block)) + << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection"); drop_connection(context, false, false); ++m_sync_bad_spans_downloaded; return 1; @@ -1465,6 +1502,14 @@ namespace cryptonote bool parent_known = m_core.have_block(new_block.prev_id); if (!parent_known) { + const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id); + if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height) + { + MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id); + drop_connection(span_connection_id); + return 1; + } + // it could be: // - later in the current chain // - later in an alt chain @@ -2093,7 +2138,6 @@ skip: m_block_queue.flush_stale_spans(live_connections); // if we don't need to get next span, and the block queue is full enough, wait a bit - bool start_from_current_chain = false; if (!force_next_span) { do @@ -2116,7 +2160,7 @@ skip: return false; } MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done"); - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height()) on_connection_synchronized(); return true; @@ -2265,7 +2309,7 @@ skip: return false; } MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done"); - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height()) on_connection_synchronized(); return true; @@ -2378,7 +2422,7 @@ skip: const uint64_t blockchain_height = m_core.get_current_blockchain_height(); if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height()) { - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); MLOG_PEER_STATE("Nothing to do for now, switching to normal state"); return true; } @@ -2421,14 +2465,11 @@ skip: m_core.get_short_chain_history(r.block_ids); CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty"); - if (!start_from_current_chain) + // we'll want to start off from where we are on that peer, which may not be added yet + if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash) { - // we'll want to start off from where we are on that peer, which may not be added yet - if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash) - { - context.m_expect_height = std::numeric_limits<uint64_t>::max(); - r.block_ids.push_front(context.m_last_known_hash); - } + context.m_expect_height = std::numeric_limits<uint64_t>::max(); + r.block_ids.push_front(context.m_last_known_hash); } handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?) @@ -2441,7 +2482,7 @@ skip: context.m_last_request_time = boost::posix_time::microsec_clock::universal_time(); context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID; - MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain); + MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size()); post_notify<NOTIFY_REQUEST_CHAIN>(r, context); MLOG_PEER_STATE("requesting chain"); }else @@ -2455,7 +2496,7 @@ skip: << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size() << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]"); - context.m_state = cryptonote_connection_context::state_normal; + context.set_state_normal(); if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height()) { if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height()) @@ -2628,11 +2669,14 @@ skip: return 1; } + context.m_expected_heights_start = arg.start_height; + + context.m_expected_heights.clear(); + context.m_expected_heights.reserve(arg.m_block_ids.size()); context.m_needed_objects.clear(); context.m_needed_objects.reserve(arg.m_block_ids.size()); uint64_t added = 0; std::unordered_set<crypto::hash> blocks_found; - bool first = true; bool expect_unknown = false; for (size_t i = 0; i < arg.m_block_ids.size(); ++i) { @@ -2644,9 +2688,10 @@ skip: } int where; const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where); - if (first) + if (i == 0) { - if (!have_block && !m_block_queue.requested(arg.m_block_ids[i]) && !m_block_queue.have(arg.m_block_ids[i])) + // our outgoing chainlist only has proven blocks (i.e. downloaded) + if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height) { LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection"); drop_connection_with_score(context, 5, false); @@ -2655,7 +2700,7 @@ skip: if (!have_block) expect_unknown = true; } - if (!first) + if (0 < i) { // after the first, blocks may be known or unknown, but if they are known, // they should be at the same height if on the main chain @@ -2696,10 +2741,10 @@ skip: expect_unknown = true; } const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i]; + context.m_expected_heights.push_back(arg.m_block_ids[i]); context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight)); if (++added == n_use_blocks) break; - first = false; } context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks; @@ -2908,6 +2953,16 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> + void t_cryptonote_protocol_handler<t_core>::drop_connection(const boost::uuids::uuid& id) + { + m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ + // This _could be_ outside of strand, so careful on actions + drop_connection(context, true, false); + return true; + }); + } + //------------------------------------------------------------------------------------------------------------------------ + template<class t_core> void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address) { MWARNING("dropping connections to " << address.str()); @@ -2924,6 +2979,7 @@ skip: { m_block_queue.flush_spans(id, true); m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ + // This _could be_ outside of strand, so careful on actions drop_connection(context, true, false); return true; }); diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 92034a435..378123c7d 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -396,6 +396,8 @@ namespace levin for (auto& connection : connections) { std::sort(connection.first.begin(), connection.first.end()); // don't leak receive order + connection.first.erase(std::unique(connection.first.begin(), connection.first.end()), + connection.first.end()); make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, true); } diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 20c906141..087a4e48b 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -696,6 +696,16 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args) std::ifstream ifs(ban_list_path.string()); for (std::string line; std::getline(ifs, line); ) { + // ignore comments after '#' character + const size_t pound_idx = line.find('#'); + if (pound_idx != std::string::npos) + line.resize(pound_idx); + + // trim whitespace and ignore empty lines + boost::trim(line); + if (line.empty()) + continue; + auto subnet = net::get_ipv4_subnet_address(line); if (subnet) { diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp index d70ece229..c770a6e22 100644 --- a/src/device/device_default.cpp +++ b/src/device/device_default.cpp @@ -317,13 +317,15 @@ namespace hw { { // sending change to yourself; derivation = a*R r = generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", <viewkey>)"); } else { // sending to the recipient; derivation = r*A (or s*C in the subaddress scheme) - r = generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")"); + const crypto::secret_key &tx_privkey{dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key}; + r = generate_key_derivation(dst_entr.addr.m_view_public_key, tx_privkey, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" + << dst_entr.addr.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{tx_privkey} << ")"); } if (need_additional_txkeys) diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index a4b5f3ef0..5d0afe1ee 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -527,6 +527,7 @@ namespace hw { {0x2c97, 0x0004, 0, 0xffa0}, {0x2c97, 0x0005, 0, 0xffa0}, {0x2c97, 0x0006, 0, 0xffa0}, + {0x2c97, 0x0007, 0, 0xffa0}, }; bool device_ledger::connect(void) { diff --git a/src/lmdb/key_stream.h b/src/lmdb/key_stream.h index 11fa284dd..74cb536e5 100644 --- a/src/lmdb/key_stream.h +++ b/src/lmdb/key_stream.h @@ -133,6 +133,7 @@ namespace lmdb //! \pre `!is_end()` \return Current key K get_key() const noexcept { + static_assert(std::is_trivially_copyable<K>(), "key is not memcpy safe"); assert(!is_end()); K out; std::memcpy(std::addressof(out), key.data(), sizeof(out)); diff --git a/src/lmdb/table.h b/src/lmdb/table.h index 4ded4ba54..48b94bc66 100644 --- a/src/lmdb/table.h +++ b/src/lmdb/table.h @@ -55,7 +55,7 @@ namespace lmdb static expect<F> get_value(MDB_val value) noexcept { static_assert(std::is_same<U, V>(), "bad MONERO_FIELD?"); - static_assert(std::is_pod<F>(), "F must be POD"); + static_assert(std::is_trivially_copyable<F>(), "F must be memcpy safe"); static_assert(sizeof(F) + offset <= sizeof(U), "bad field type and/or offset"); if (value.mv_size != sizeof(U)) diff --git a/src/lmdb/util.h b/src/lmdb/util.h index c6c75bc00..038411417 100644 --- a/src/lmdb/util.h +++ b/src/lmdb/util.h @@ -111,6 +111,7 @@ namespace lmdb template<typename T, std::size_t offset = 0> inline int less(MDB_val const* left, MDB_val const* right) noexcept { + static_assert(std::is_trivially_copyable<T>(), "memcpy will not work"); if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset) { assert("invalid use of custom comparison" == 0); @@ -127,7 +128,7 @@ namespace lmdb /*! A LMDB comparison function that uses `std::memcmp`. - \toaram T is `!epee::has_padding` + \toaram T has standard layout and an alignment of 1 \tparam offset to `T` within the value. \return The result of `std::memcmp` over the value. @@ -135,7 +136,7 @@ namespace lmdb template<typename T, std::size_t offset = 0> inline int compare(MDB_val const* left, MDB_val const* right) noexcept { - static_assert(!epee::has_padding<T>(), "memcmp will not work"); + static_assert(std::is_standard_layout<T>() && alignof(T) == 1, "memcmp will not work"); if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset) { assert("invalid use of custom comparison" == 0); diff --git a/src/lmdb/value_stream.h b/src/lmdb/value_stream.h index bd2814ef4..2475ec191 100644 --- a/src/lmdb/value_stream.h +++ b/src/lmdb/value_stream.h @@ -162,8 +162,8 @@ namespace lmdb G get_value() const noexcept { static_assert(std::is_same<U, T>(), "bad MONERO_FIELD usage?"); - static_assert(std::is_pod<U>(), "value type must be pod"); - static_assert(std::is_pod<G>(), "field type must be pod"); + static_assert(std::is_trivially_copyable<U>(), "value type must be memcpy safe"); + static_assert(std::is_trivially_copyable<G>(), "field type must be memcpy safe"); static_assert(sizeof(G) + uoffset <= sizeof(U), "bad field and/or offset"); assert(sizeof(G) + uoffset <= values.size()); assert(!is_end()); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 98d8ecfff..cbdeef7e3 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -125,7 +125,8 @@ namespace nodetool template<class t_payload_net_handler> class node_server: public epee::levin::levin_commands_handler<p2p_connection_context_t<typename t_payload_net_handler::connection_context> >, public i_p2p_endpoint<typename t_payload_net_handler::connection_context>, - public epee::net_utils::i_connection_filter + public epee::net_utils::i_connection_filter, + public epee::net_utils::i_connection_limit { struct by_conn_id{}; struct by_peer_id{}; @@ -351,7 +352,10 @@ namespace nodetool virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1); //----------------- i_connection_filter -------------------------------------------------------- virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t = NULL); + //----------------- i_connection_limit --------------------------------------------------------- + virtual bool is_host_limit(const epee::net_utils::network_address &address); //----------------------------------------------------------------------------------------------- + bool parse_peer_from_string(epee::net_utils::network_address& pe, const std::string& node_addr, uint16_t default_port = 0); bool handle_command_line( const boost::program_options::variables_map& vm diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 71f5393e8..e1a1db9a8 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -228,6 +228,26 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> + bool node_server<t_payload_net_handler>::is_host_limit(const epee::net_utils::network_address &address) + { + const network_zone& zone = m_network_zones.at(address.get_zone()); + if (zone.m_current_number_of_in_peers >= zone.m_config.m_net_config.max_in_connection_count) // in peers limit + { + MWARNING("Exceeded max incoming connections, so dropping this one."); + return true; + } + + if(has_too_many_connections(address)) + { + MWARNING("CONNECTION FROM " << address.host_str() << " REFUSED, too many connections from the same address"); + return true; + } + + return false; + } + + //----------------------------------------------------------------------------------- + template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds, bool add_only) { if(!addr.is_blockable()) @@ -531,6 +551,16 @@ namespace nodetool std::istringstream iss(banned_ips); for (std::string line; std::getline(iss, line); ) { + // ignore comments after '#' character + const size_t pound_idx = line.find('#'); + if (pound_idx != std::string::npos) + line.resize(pound_idx); + + // trim whitespace and ignore empty lines + boost::trim(line); + if (line.empty()) + continue; + auto subnet = net::get_ipv4_subnet_address(line); if (subnet) { @@ -709,7 +739,7 @@ namespace nodetool full_addrs.insert("51.79.173.165:28080"); full_addrs.insert("192.99.8.110:28080"); full_addrs.insert("37.187.74.171:28080"); - full_addrs.insert("77.172.183.193:28080"); + full_addrs.insert("88.99.195.15:28080"); } else if (m_nettype == cryptonote::STAGENET) { @@ -717,7 +747,7 @@ namespace nodetool full_addrs.insert("51.79.173.165:38080"); full_addrs.insert("192.99.8.110:38080"); full_addrs.insert("37.187.74.171:38080"); - full_addrs.insert("77.172.183.193:38080"); + full_addrs.insert("88.99.195.15:38080"); } else if (m_nettype == cryptonote::FAKECHAIN) { @@ -730,7 +760,7 @@ namespace nodetool full_addrs.insert("51.79.173.165:18080"); full_addrs.insert("192.99.8.110:18080"); full_addrs.insert("37.187.74.171:18080"); - full_addrs.insert("77.172.183.193:18080"); + full_addrs.insert("88.99.195.15:18080"); } return full_addrs; } @@ -971,6 +1001,7 @@ namespace nodetool std::string ipv6_addr = ""; std::string ipv6_port = ""; zone.second.m_net_server.set_connection_filter(this); + zone.second.m_net_server.set_connection_limit(this); MINFO("Binding (IPv4) on " << zone.second.m_bind_ip << ":" << zone.second.m_port); if (!zone.second.m_bind_ipv6_address.empty() && m_use_ipv6) { @@ -2483,6 +2514,20 @@ namespace nodetool std::vector<peerlist_entry> local_peerlist_new; zone.m_peerlist.get_peerlist_head(local_peerlist_new, true, max_peerlist_size); + /* Tor/I2P nodes receiving connections via forwarding (from tor/i2p daemon) + do not know the address of the connecting peer. This is relayed to them, + iff the node has setup an inbound hidden service. + + \note Insert into `local_peerlist_new` so that it is only sent once like + the other peers. */ + if(outgoing_to_same_zone) + { + local_peerlist_new.insert( + local_peerlist_new.begin() + crypto::rand_range(std::size_t(0), local_peerlist_new.size()), + peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, 0} + ); + } + //only include out peers we did not already send rsp.local_peerlist_new.reserve(local_peerlist_new.size()); for (auto &pe: local_peerlist_new) @@ -2493,17 +2538,6 @@ namespace nodetool } m_payload_handler.get_payload_sync_data(rsp.payload_data); - /* Tor/I2P nodes receiving connections via forwarding (from tor/i2p daemon) - do not know the address of the connecting peer. This is relayed to them, - iff the node has setup an inbound hidden service. The other peer will have - to use the random peer_id value to link the two. My initial thought is that - the inbound peer should leave the other side marked as `<unknown tor host>`, - etc., because someone could give faulty addresses over Tor/I2P to get the - real peer with that identity banned/blacklisted. */ - - if(outgoing_to_same_zone) - rsp.local_peerlist_new.push_back(peerlist_entry{zone.m_our_address, zone.m_config.m_peer_id, std::time(nullptr)}); - LOG_DEBUG_CC(context, "COMMAND_TIMED_SYNC"); return 1; } @@ -2547,13 +2581,6 @@ namespace nodetool return 1; } - if (zone.m_current_number_of_in_peers >= zone.m_config.m_net_config.max_in_connection_count) // in peers limit - { - LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but already have max incoming connections, so dropping this one."); - drop_connection(context); - return 1; - } - if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true)) { LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection."); @@ -2563,13 +2590,6 @@ namespace nodetool zone.m_notifier.on_handshake_complete(context.m_connection_id, context.m_is_income); - if(has_too_many_connections(context.m_remote_address)) - { - LOG_PRINT_CCONTEXT_L1("CONNECTION FROM " << context.m_remote_address.host_str() << " REFUSED, too many connections from the same address"); - drop_connection(context); - return 1; - } - //associate peer_id with this connection context.peer_id = arg.node_data.peer_id; context.m_in_timedsync = false; @@ -2889,15 +2909,16 @@ namespace nodetool if (cntxt.m_is_income && cntxt.m_remote_address.is_same_host(address)) { count++; - if (count > max_connections) { + // the only call location happens BEFORE foreach_connection list is updated + if (count >= max_connections) { return false; } } return true; }); - - return count > max_connections; + // the only call location happens BEFORE foreach_connection list is updated + return count >= max_connections; } template<class t_payload_net_handler> diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 0ad80f41e..1b0e3f261 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -2808,6 +2808,12 @@ namespace cryptonote } else { + if (!i->ip) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "No ip/host supplied"; + return false; + } na = epee::net_utils::ipv4_network_address{i->ip, 0}; } if (i->ban) diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 11ab80666..b13663ac9 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -520,6 +520,8 @@ namespace rpc res.info.target_height = res.info.height; } + m_core.get_blockchain_top(res.info.top_block_height, res.info.top_block_hash); + auto& chain = m_core.get_blockchain_storage(); res.info.wide_difficulty = chain.get_difficulty_for_next_block(); diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index dd9d198ed..7f3b787b6 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -176,6 +176,7 @@ namespace rpc { uint64_t height; uint64_t target_height; + uint64_t top_block_height; cryptonote::difficulty_type wide_difficulty; uint64_t difficulty; uint64_t target; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index 43d9cfebe..8580f93b8 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -273,7 +273,10 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t { INSERT_INTO_JSON_OBJECT(dest, signatures, tx.signatures); } - INSERT_INTO_JSON_OBJECT(dest, ringct, tx.rct_signatures); + { + dest.Key("ringct"); + toJsonValue(dest, tx.rct_signatures, tx.pruned); + } dest.EndObject(); } @@ -1111,7 +1114,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResp GET_FROM_JSON_OBJECT(val, response.reward, reward); } -void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig) +void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig, const bool prune) { using boost::adaptors::transform; @@ -1131,7 +1134,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& } // prunable - if (!sig.p.bulletproofs.empty() || !sig.p.bulletproofs_plus.empty() || !sig.p.rangeSigs.empty() || !sig.p.MGs.empty() || !sig.get_pseudo_outs().empty()) + if (!prune && (!sig.p.bulletproofs.empty() || !sig.p.bulletproofs_plus.empty() || !sig.p.rangeSigs.empty() || !sig.p.MGs.empty() || !sig.get_pseudo_outs().empty())) { dest.Key("prunable"); dest.StartObject(); @@ -1423,9 +1426,14 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r { dest.StartObject(); + const uint64_t difficulty_top64 = (info.wide_difficulty >> 64).convert_to<std::uint64_t>(); + const uint64_t cumulative_difficulty_top64 = (info.wide_cumulative_difficulty >> 64).convert_to<std::uint64_t>(); + INSERT_INTO_JSON_OBJECT(dest, height, info.height); INSERT_INTO_JSON_OBJECT(dest, target_height, info.target_height); + INSERT_INTO_JSON_OBJECT(dest, top_block_height, info.top_block_height); INSERT_INTO_JSON_OBJECT(dest, difficulty, info.difficulty); + INSERT_INTO_JSON_OBJECT(dest, difficulty_top64, difficulty_top64); INSERT_INTO_JSON_OBJECT(dest, target, info.target); INSERT_INTO_JSON_OBJECT(dest, tx_count, info.tx_count); INSERT_INTO_JSON_OBJECT(dest, tx_pool_size, info.tx_pool_size); @@ -1440,12 +1448,14 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::r INSERT_INTO_JSON_OBJECT(dest, nettype, info.nettype); INSERT_INTO_JSON_OBJECT(dest, top_block_hash, info.top_block_hash); INSERT_INTO_JSON_OBJECT(dest, cumulative_difficulty, info.cumulative_difficulty); + INSERT_INTO_JSON_OBJECT(dest, cumulative_difficulty_top64, cumulative_difficulty_top64); INSERT_INTO_JSON_OBJECT(dest, block_size_limit, info.block_size_limit); INSERT_INTO_JSON_OBJECT(dest, block_weight_limit, info.block_weight_limit); INSERT_INTO_JSON_OBJECT(dest, block_size_median, info.block_size_median); INSERT_INTO_JSON_OBJECT(dest, block_weight_median, info.block_weight_median); INSERT_INTO_JSON_OBJECT(dest, adjusted_time, info.adjusted_time); INSERT_INTO_JSON_OBJECT(dest, start_time, info.start_time); + INSERT_INTO_JSON_OBJECT(dest, version, info.version); dest.EndObject(); } @@ -1457,9 +1467,14 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf throw WRONG_TYPE("json object"); } + uint64_t difficulty_top64 = 0; + uint64_t cumulative_difficulty_top64 = 0; + GET_FROM_JSON_OBJECT(val, info.height, height); GET_FROM_JSON_OBJECT(val, info.target_height, target_height); + GET_FROM_JSON_OBJECT(val, info.top_block_height, top_block_height); GET_FROM_JSON_OBJECT(val, info.difficulty, difficulty); + GET_FROM_JSON_OBJECT(val, difficulty_top64, difficulty_top64); GET_FROM_JSON_OBJECT(val, info.target, target); GET_FROM_JSON_OBJECT(val, info.tx_count, tx_count); GET_FROM_JSON_OBJECT(val, info.tx_pool_size, tx_pool_size); @@ -1474,12 +1489,22 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf GET_FROM_JSON_OBJECT(val, info.nettype, nettype); GET_FROM_JSON_OBJECT(val, info.top_block_hash, top_block_hash); GET_FROM_JSON_OBJECT(val, info.cumulative_difficulty, cumulative_difficulty); + GET_FROM_JSON_OBJECT(val, cumulative_difficulty_top64, cumulative_difficulty_top64); GET_FROM_JSON_OBJECT(val, info.block_size_limit, block_size_limit); GET_FROM_JSON_OBJECT(val, info.block_weight_limit, block_weight_limit); GET_FROM_JSON_OBJECT(val, info.block_size_median, block_size_median); GET_FROM_JSON_OBJECT(val, info.block_weight_median, block_weight_median); GET_FROM_JSON_OBJECT(val, info.adjusted_time, adjusted_time); GET_FROM_JSON_OBJECT(val, info.start_time, start_time); + GET_FROM_JSON_OBJECT(val, info.version, version); + + info.wide_difficulty = difficulty_top64; + info.wide_difficulty <<= 64; + info.wide_difficulty += info.difficulty; + + info.wide_cumulative_difficulty = cumulative_difficulty_top64; + info.wide_cumulative_difficulty <<= 64; + info.wide_cumulative_difficulty += info.cumulative_difficulty; } void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::output_distribution& dist) diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h index 3868ab3f8..bbcde9bf6 100644 --- a/src/serialization/json_object.h +++ b/src/serialization/json_object.h @@ -281,7 +281,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error); void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::rpc::BlockHeaderResponse& response); void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response); -void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& i); +void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig& sig, bool prune); void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig); void fromJsonValue(const rapidjson::Value& val, rct::ctkey& key); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 2c51337ef..89691e9f7 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2034,7 +2034,7 @@ bool simple_wallet::rpc_payment_info(const std::vector<std::string> &args) crypto::public_key pkey; crypto::secret_key_to_public_key(m_wallet->get_rpc_client_secret_key(), pkey); message_writer() << tr("RPC client ID: ") << pkey; - message_writer() << tr("RPC client secret key: ") << m_wallet->get_rpc_client_secret_key(); + message_writer() << tr("RPC client secret key: ") << crypto::secret_key_explicit_print_ref{m_wallet->get_rpc_client_secret_key()}; if (!m_wallet->get_rpc_payment_info(false, payment_required, credits, diff, credits_per_hash_found, hashing_blob, height, seed_height, seed_hash, next_seed_hash, cookie)) { fail_msg_writer() << tr("Failed to query daemon"); @@ -8186,9 +8186,9 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_) std::string get_tx_key_stream(crypto::secret_key tx_key, std::vector<crypto::secret_key> additional_tx_keys) { ostringstream oss; - oss << epee::string_tools::pod_to_hex(tx_key); + oss << epee::string_tools::pod_to_hex(unwrap(unwrap(tx_key))); for (size_t i = 0; i < additional_tx_keys.size(); ++i) - oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]); + oss << epee::string_tools::pod_to_hex(unwrap(unwrap(additional_tx_keys[i]))); return oss.str(); } diff --git a/src/version.cpp.in b/src/version.cpp.in index ac6ebaa89..857fa3588 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" -#define DEF_MONERO_VERSION "0.18.3.3" +#define DEF_MONERO_VERSION "0.18.3.4" #define DEF_MONERO_RELEASE_NAME "Fluorine Fermi" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG #define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e9f76f4cf..8fda0bab7 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -921,7 +921,7 @@ std::string WalletImpl::integratedAddress(const std::string &payment_id) const std::string WalletImpl::secretViewKey() const { - return epee::string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key); + return epee::string_tools::pod_to_hex(unwrap(unwrap(m_wallet->get_account().get_keys().m_view_secret_key))); } std::string WalletImpl::publicViewKey() const @@ -931,7 +931,7 @@ std::string WalletImpl::publicViewKey() const std::string WalletImpl::secretSpendKey() const { - return epee::string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key); + return epee::string_tools::pod_to_hex(unwrap(unwrap(m_wallet->get_account().get_keys().m_spend_secret_key))); } std::string WalletImpl::publicSpendKey() const @@ -2043,9 +2043,9 @@ std::string WalletImpl::getTxKey(const std::string &txid_str) const { clearStatus(); std::ostringstream oss; - oss << epee::string_tools::pod_to_hex(tx_key); + oss << epee::string_tools::pod_to_hex(unwrap(unwrap(tx_key))); for (size_t i = 0; i < additional_tx_keys.size(); ++i) - oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]); + oss << epee::string_tools::pod_to_hex(unwrap(unwrap(additional_tx_keys[i]))); return oss.str(); } else diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e8991a326..dfb8b23cb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1287,6 +1287,11 @@ bool wallet2::has_stagenet_option(const boost::program_options::variables_map& v return command_line::get_arg(vm, options().stagenet); } +bool wallet2::has_proxy_option() const +{ + return !m_proxy.empty(); +} + std::string wallet2::device_name_option(const boost::program_options::variables_map& vm) { return command_line::get_arg(vm, options().hw_device); @@ -1371,12 +1376,15 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia } //---------------------------------------------------------------------------------------------------- -bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options) +bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options, const std::string& proxy) { boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex); if(m_http_client->is_connected()) m_http_client->disconnect(); + CHECK_AND_ASSERT_MES2(m_proxy.empty() || proxy.empty() , "It is not possible to set global proxy (--proxy) and daemon specific proxy together."); + if(m_proxy.empty()) + CHECK_AND_ASSERT_MES(set_proxy(proxy), false, "failed to set proxy address"); const bool changed = m_daemon_address != daemon_address; m_daemon_address = std::move(daemon_address); m_daemon_login = std::move(daemon_login); @@ -1411,7 +1419,8 @@ bool wallet2::set_proxy(const std::string &address) //---------------------------------------------------------------------------------------------------- bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, const std::string &proxy_address, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options) { - CHECK_AND_ASSERT_MES(set_proxy(proxy_address), false, "failed to set proxy address"); + m_proxy = proxy_address; + CHECK_AND_ASSERT_MES(set_proxy(m_proxy), false, "failed to set proxy address"); m_checkpoints.init_default_checkpoints(m_nettype); m_is_initialized = true; m_upper_transaction_weight_limit = upper_transaction_weight_limit; @@ -3015,6 +3024,8 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids, uint64_t gra size_t sz = blockchain_size - m_blockchain.offset(); if(!sz) { + if(m_blockchain.size() > m_blockchain.offset()) + ids.push_back(m_blockchain[m_blockchain.offset()]); ids.push_back(m_blockchain.genesis()); return; } @@ -3687,6 +3698,7 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, req.requested_info = COMMAND_RPC_GET_BLOCKS_FAST::POOL_ONLY; req.pool_info_since = m_pool_info_query_time; + req.prune = true; { const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex}; @@ -4749,7 +4761,7 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const crypt original_address = get_account_address_as_str(m_nettype, false, m_original_address); value.SetString(original_address.c_str(), original_address.length()); json.AddMember("original_address", value, json.GetAllocator()); - original_view_secret_key = epee::string_tools::pod_to_hex(m_original_view_secret_key); + original_view_secret_key = epee::string_tools::pod_to_hex(unwrap(unwrap(m_original_view_secret_key))); value.SetString(original_view_secret_key.c_str(), original_view_secret_key.length()); json.AddMember("original_view_secret_key", value, json.GetAllocator()); } @@ -7505,7 +7517,7 @@ void wallet2::commit_tx(pending_tx& ptx) cryptonote::COMMAND_RPC_SUBMIT_RAW_TX::request oreq; cryptonote::COMMAND_RPC_SUBMIT_RAW_TX::response ores; oreq.address = get_account().get_public_address_str(m_nettype); - oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + oreq.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); { const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex}; @@ -8435,7 +8447,7 @@ bool wallet2::sign_multisig_tx_from_file(const std::string &filename, std::vecto return sign_multisig_tx_to_file(exported_txs, filename, txids); } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask) const +uint64_t wallet2::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask) { if (use_per_byte_fee) { @@ -10531,7 +10543,7 @@ bool wallet2::light_wallet_login(bool &new_address) tools::COMMAND_RPC_LOGIN::request request; tools::COMMAND_RPC_LOGIN::response response; request.address = get_account().get_public_address_str(m_nettype); - request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + request.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); // Always create account if it doesn't exist. request.create_account = true; m_daemon_rpc_mutex.lock(); @@ -10558,7 +10570,7 @@ bool wallet2::light_wallet_import_wallet_request(tools::COMMAND_RPC_IMPORT_WALLE MDEBUG("Light wallet import wallet request"); tools::COMMAND_RPC_IMPORT_WALLET_REQUEST::request oreq; oreq.address = get_account().get_public_address_str(m_nettype); - oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + oreq.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); m_daemon_rpc_mutex.lock(); bool r = invoke_http_json("/import_wallet_request", oreq, response, rpc_timeout, "POST"); m_daemon_rpc_mutex.unlock(); @@ -10577,7 +10589,7 @@ void wallet2::light_wallet_get_unspent_outs() oreq.amount = "0"; oreq.address = get_account().get_public_address_str(m_nettype); - oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + oreq.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); // openMonero specific oreq.dust_threshold = boost::lexical_cast<std::string>(::config::DEFAULT_DUST_THRESHOLD); // below are required by openMonero api - but are not used. @@ -10729,7 +10741,7 @@ bool wallet2::light_wallet_get_address_info(tools::COMMAND_RPC_GET_ADDRESS_INFO: tools::COMMAND_RPC_GET_ADDRESS_INFO::request request; request.address = get_account().get_public_address_str(m_nettype); - request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + request.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); m_daemon_rpc_mutex.lock(); bool r = invoke_http_json("/get_address_info", request, response, rpc_timeout, "POST"); m_daemon_rpc_mutex.unlock(); @@ -10746,7 +10758,7 @@ void wallet2::light_wallet_get_address_txs() tools::COMMAND_RPC_GET_ADDRESS_TXS::response ires; ireq.address = get_account().get_public_address_str(m_nettype); - ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key); + ireq.view_key = string_tools::pod_to_hex(unwrap(unwrap(get_account().get_keys().m_view_secret_key))); m_daemon_rpc_mutex.lock(); bool r = invoke_http_json("/get_address_txs", ireq, ires, rpc_timeout, "POST"); m_daemon_rpc_mutex.unlock(); @@ -10976,7 +10988,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image, const account_keys& ack = get_account().get_keys(); crypto::key_derivation derivation; bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); + CHECK_AND_ASSERT_MES(r, false, "failed to generate_key_derivation(" << tx_public_key << ", " << crypto::secret_key_explicit_print_ref{ack.m_view_secret_key} << ")"); r = crypto::derive_public_key(derivation, out_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub); CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key (" << derivation << ", " << out_index << ", " << ack.m_account_address.m_spend_public_key << ")"); @@ -10984,7 +10996,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image, crypto::derive_secret_key(derivation, out_index, ack.m_spend_secret_key, in_ephemeral.sec); crypto::public_key out_pkey_test; r = crypto::secret_key_to_public_key(in_ephemeral.sec, out_pkey_test); - CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key(" << in_ephemeral.sec << ")"); + CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key(" << crypto::secret_key_explicit_print_ref{in_ephemeral.sec} << ")"); CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_pkey_test, false, "derived secret key doesn't match derived public key"); crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, calculated_key_image); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d648cd5d3..2f4ad52f1 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1039,6 +1039,12 @@ private: std::string path() const; /*! + * \brief has_proxy_option Check the global proxy (--proxy) has been defined or not. + * \return returns bool representing the global proxy (--proxy). + */ + bool has_proxy_option() const; + + /*! * \brief verifies given password is correct for default wallet keys file */ bool verify_password(const epee::wipeable_string& password) {crypto::secret_key key = crypto::null_skey; return verify_password(password, key);}; @@ -1069,7 +1075,8 @@ private: epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); bool set_daemon(std::string daemon_address = "http://localhost:8080", boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true, - epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); + epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, + const std::string &proxy = ""); bool set_proxy(const std::string &address); void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); } @@ -1651,7 +1658,7 @@ private: std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels); std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees); - uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask) const; + static uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask); uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1); uint64_t get_base_fee(uint32_t priority); uint64_t get_base_fee(); @@ -1949,6 +1956,7 @@ private: cryptonote::account_base m_account; boost::optional<epee::net_utils::http::login> m_daemon_login; std::string m_daemon_address; + std::string m_proxy; std::string m_wallet_file; std::string m_keys_file; std::string m_mms_file; @@ -2568,7 +2576,7 @@ namespace boost bool use_bulletproofs = x.rct_config.range_proof_type != rct::RangeProofBorromean; a & use_bulletproofs; if (!typename Archive::is_saving()) - x.rct_config = { use_bulletproofs ? rct::RangeProofBulletproof : rct::RangeProofBorromean, 0 }; + x.rct_config = { use_bulletproofs ? rct::RangeProofPaddedBulletproof : rct::RangeProofBorromean, 0 }; return; } a & x.rct_config; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d24b4c563..14c66c5f5 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1312,9 +1312,9 @@ namespace tools res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); if (req.get_tx_keys) { - res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); + res.tx_key_list.push_back(epee::string_tools::pod_to_hex(unwrap(unwrap(ptx.tx_key)))); for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys) - res.tx_key_list.back() += epee::string_tools::pod_to_hex(additional_tx_key); + res.tx_key_list.back() += epee::string_tools::pod_to_hex(unwrap(unwrap(additional_tx_key))); } } @@ -3625,7 +3625,7 @@ namespace tools if (!wal) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to open wallet"; + er.message = "Failed to open wallet : " + (!er.message.empty() ? er.message : "Unknown."); return false; } @@ -4600,6 +4600,13 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + + if (m_wallet->has_proxy_option() && !req.proxy.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_PROXY_ALREADY_DEFINED; + er.message = "It is not possible to set daemon specific proxy when --proxy is defined."; + return false; + } std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints; ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size()); @@ -4643,7 +4650,7 @@ namespace tools if (!req.username.empty() || !req.password.empty()) daemon_login.emplace(req.username, req.password); - if (!m_wallet->set_daemon(req.address, daemon_login, req.trusted, std::move(ssl_options))) + if (!m_wallet->set_daemon(req.address, daemon_login, req.trusted, std::move(ssl_options), req.proxy)) { er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; er.message = std::string("Unable to set daemon"); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index a44b56ed6..72a35eb73 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -2598,6 +2598,7 @@ namespace wallet_rpc std::string ssl_ca_file; std::vector<std::string> ssl_allowed_fingerprints; bool ssl_allow_any_cert; + std::string proxy; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) @@ -2610,6 +2611,7 @@ namespace wallet_rpc KV_SERIALIZE(ssl_ca_file) KV_SERIALIZE(ssl_allowed_fingerprints) KV_SERIALIZE_OPT(ssl_allow_any_cert, false) + KV_SERIALIZE_OPT(proxy, (std::string)"") END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; diff --git a/tests/benchmark.cpp b/tests/benchmark.cpp index 6a845d61a..660783dd9 100644 --- a/tests/benchmark.cpp +++ b/tests/benchmark.cpp @@ -109,7 +109,7 @@ namespace template<typename T> bool compare(const T& lhs, const T& rhs) noexcept { - static_assert(!epee::has_padding<T>(), "type might have padding"); + static_assert(std::is_standard_layout<T>() && alignof(T) == 1, "type might have padding"); return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(T)) == 0; } diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index 966c76116..1d3a6a3a1 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -227,13 +227,13 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry CHECK_AND_ASSERT_MES(r, false, "Failed to generate multisig export key image"); } MDEBUG("Party " << msidx << ":"); - MDEBUG("spend: sec " << miner_account[msidx].get_keys().m_spend_secret_key << ", pub " << miner_account[msidx].get_keys().m_account_address.m_spend_public_key); - MDEBUG("view: sec " << miner_account[msidx].get_keys().m_view_secret_key << ", pub " << miner_account[msidx].get_keys().m_account_address.m_view_public_key); + MDEBUG("spend: sec " << crypto::secret_key_explicit_print_ref{miner_account[msidx].get_keys().m_spend_secret_key} << ", pub " << miner_account[msidx].get_keys().m_account_address.m_spend_public_key); + MDEBUG("view: sec " << crypto::secret_key_explicit_print_ref{miner_account[msidx].get_keys().m_view_secret_key} << ", pub " << miner_account[msidx].get_keys().m_account_address.m_view_public_key); for (const auto &k: miner_account[msidx].get_multisig_keys()) - MDEBUG("msk: " << k); + MDEBUG("msk: " << crypto::secret_key_explicit_print_ref{k}); for (size_t n = 0; n < account_k[msidx][tdidx].size(); ++n) { - MDEBUG("k: " << account_k[msidx][tdidx][n]); + MDEBUG("k: " << crypto::secret_key_explicit_print_ref{account_k[msidx][tdidx][n]}); MDEBUG("L: " << account_L[msidx][tdidx][n]); MDEBUG("R: " << account_R[msidx][tdidx][n]); } @@ -406,7 +406,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry MDEBUG("signing with k " << k.back()[n]); MDEBUG("signing with sk " << skey); for (const auto &sk: used_keys) - MDEBUG(" created with sk " << sk); + MDEBUG(" created with sk " << crypto::secret_key_explicit_print_ref{sk}); CHECK_AND_ASSERT_MES(signer_tx_builder.next_partial_sign(sig.total_alpha_G, sig.total_alpha_H, k, skey, sig.c_0, sig.s), false, "error: multisig::signing::tx_builder_ringct_t::next_partial_sign"); // in round-robin signing, the last signer finalizes the tx diff --git a/tests/create_test_disks.sh b/tests/create_test_disks.sh new file mode 100755 index 000000000..8e17c732d --- /dev/null +++ b/tests/create_test_disks.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +set -e + +LOOP_DEVICE_MAJOR=7 +LOOP_DEVICE_MIN_ID=100 + +echo_err() { + echo "$@" >&2 +} + +root_exec() { + if [[ $EUID -ne 0 ]]; then + ${ROOT_EXEC_CMD:-sudo} "$@" + else + "$@" + fi +} + +create_device_node() { + local -r last_id=$(find /dev/ -name 'loop[0-9]*' -printf '%f\n' | sed 's/^loop//' | sort -r -n | head -1) + local id=$((last_id + 1)) + if [[ "$id" -lt "$LOOP_DEVICE_MIN_ID" ]]; then + id="$LOOP_DEVICE_MIN_ID" + fi + local path + for (( i=0; i<10; i++ )); do + path="/dev/loop$id" + if [[ ! -e "$path" ]] && root_exec mknod "$path" b "$LOOP_DEVICE_MAJOR" "$id"; then + echo "$path" + return 0 + fi + $((id++)) + done + return 1 +} + +device_mountpoint() { + local -r datadir="$1" + local -r dev="$2" + if [[ -z "$datadir" || -z "$dev" ]]; then + echo_err "Usage: device_mountpoint <data dir> <device>" + return 1 + fi + echo "$datadir/mnt-$(basename "$dev")" +} + +create_device() { + local -r datadir="$1" + if [[ -z "$datadir" ]]; then + echo_err "Usage: create_device <data dir>" + return 1 + fi + local -r dev=$(create_device_node) + local -r fs="$datadir/$(basename "$dev").vhd" + local -r mountpoint=$(device_mountpoint "$datadir" "$dev") + echo_err + echo_err "# Device $dev" + dd if=/dev/zero of="$fs" bs=64K count=128 >/dev/null 2>&1 + root_exec losetup "$dev" "$fs" + root_exec mkfs.ext4 "$dev" >/dev/null 2>&1 + mkdir "$mountpoint" + root_exec mount "$dev" "$mountpoint" + echo "$dev" +} + +# Unused by default, but helpful for local development +destroy_device() { + local -r datadir="$1" + local -r dev="$2" + if [[ -z "$datadir" || -z "$dev" ]]; then + echo_err "Usage: destroy_device <data dir> <device>" + return 1 + fi + echo_err "Destroying device $dev" + root_exec umount $(device_mountpoint "$datadir" "$dev") + root_exec losetup -d "$dev" + root_exec rm "$dev" +} + +block_device_path() { + device_name=$(basename "$1") + device_minor=${device_name/#loop} + echo "/sys/dev/block/$LOOP_DEVICE_MAJOR:$device_minor" +} + +tmpdir=$(mktemp --tmpdir -d monerotest.XXXXXXXX) +echo_err "Creating devices using temporary directory: $tmpdir" + +dev_rot=$(create_device "$tmpdir") +bdev_rot=$(block_device_path "$dev_rot") +echo 1 | root_exec tee "$bdev_rot/queue/rotational" >/dev/null +echo MONERO_TEST_DEVICE_HDD=$(device_mountpoint "$tmpdir" "$dev_rot") + +dev_ssd=$(create_device "$tmpdir") +bdev_ssd=$(block_device_path "$dev_ssd") +echo 0 | root_exec tee "$bdev_ssd/queue/rotational" >/dev/null +echo MONERO_TEST_DEVICE_SSD=$(device_mountpoint "$tmpdir" "$dev_ssd") diff --git a/tests/data/node/banlist_1.txt b/tests/data/node/banlist_1.txt new file mode 100644 index 000000000..7cc94ca62 --- /dev/null +++ b/tests/data/node/banlist_1.txt @@ -0,0 +1,17 @@ +# magicfolk +255.255.255.0 # Saruman the White +128.128.128.0 # Gandalf the Gray +150.75.0.0 # Radagast the Brown +99.98.0.0/16 # All of Misty Mountain + +# personal enemies +1.2.3.4 # this woman used to give me swirlies +6.7.8.9 # I just don't like the cut of his jib +1.0.0.7#Literally James Bond, he wrecked my aston martin +100.98.1.13 # Earl from HOA +100.98.1.0/24 #The rest of the HOA for good measure +# + +#7.7.7.7 +#^^^We're chill now, she's truly an angel + diff --git a/tests/functional_tests/make_test_signature.cc b/tests/functional_tests/make_test_signature.cc index e9dab8bd4..09a3f51c1 100644 --- a/tests/functional_tests/make_test_signature.cc +++ b/tests/functional_tests/make_test_signature.cc @@ -48,7 +48,7 @@ int main(int argc, const char **argv) crypto::public_key pkey; crypto::random32_unbiased((unsigned char*)skey.data); crypto::secret_key_to_public_key(skey, pkey); - printf("%s %s\n", epee::string_tools::pod_to_hex(skey).c_str(), epee::string_tools::pod_to_hex(pkey).c_str()); + printf("%s %s\n", epee::string_tools::pod_to_hex(unwrap(unwrap(skey))).c_str(), epee::string_tools::pod_to_hex(pkey).c_str()); return 0; } diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp index 7f926534a..329992463 100644 --- a/tests/unit_tests/crypto.cpp +++ b/tests/unit_tests/crypto.cpp @@ -72,10 +72,10 @@ TEST(Crypto, Ostream) EXPECT_TRUE(is_formatted<crypto::hash8>()); EXPECT_TRUE(is_formatted<crypto::hash>()); EXPECT_TRUE(is_formatted<crypto::public_key>()); - EXPECT_TRUE(is_formatted<crypto::secret_key>()); EXPECT_TRUE(is_formatted<crypto::signature>()); EXPECT_TRUE(is_formatted<crypto::key_derivation>()); EXPECT_TRUE(is_formatted<crypto::key_image>()); + EXPECT_TRUE(is_formatted<rct::key>()); } TEST(Crypto, null_keys) diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp index d56cbe45b..bc3691e59 100644 --- a/tests/unit_tests/dns_resolver.cpp +++ b/tests/unit_tests/dns_resolver.cpp @@ -41,15 +41,11 @@ TEST(DNSResolver, IPv4Success) auto ips = resolver.get_ipv4("example.com", avail, valid); - ASSERT_EQ(1, ips.size()); - - //ASSERT_STREQ("93.184.216.119", ips[0].c_str()); + ASSERT_LE(1, ips.size()); ips = tools::DNSResolver::instance().get_ipv4("example.com", avail, valid); - ASSERT_EQ(1, ips.size()); - - //ASSERT_STREQ("93.184.216.119", ips[0].c_str()); + ASSERT_LE(1, ips.size()); } TEST(DNSResolver, IPv4Failure) @@ -76,9 +72,7 @@ TEST(DNSResolver, DNSSECSuccess) auto ips = resolver.get_ipv4("example.com", avail, valid); - ASSERT_EQ(1, ips.size()); - - //ASSERT_STREQ("93.184.216.119", ips[0].c_str()); + ASSERT_LE(1, ips.size()); ASSERT_TRUE(avail); ASSERT_TRUE(valid); diff --git a/tests/unit_tests/epee_serialization.cpp b/tests/unit_tests/epee_serialization.cpp index f46630615..5e5b6e40f 100644 --- a/tests/unit_tests/epee_serialization.cpp +++ b/tests/unit_tests/epee_serialization.cpp @@ -29,8 +29,11 @@ #include <cstdint> #include <gtest/gtest.h> +#include <vector> +#include "serialization/keyvalue_serialization.h" #include "storages/portable_storage.h" +#include "storages/portable_storage_template_helper.h" #include "span.h" TEST(epee_binary, two_keys) @@ -54,3 +57,68 @@ TEST(epee_binary, duplicate_key) epee::serialization::portable_storage storage{}; EXPECT_FALSE(storage.load_from_binary(data)); } + +namespace +{ + +template<typename t_param> +struct ParentObjWithOptChild +{ + t_param params; + + ParentObjWithOptChild(): params{} {} + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(params) + END_KV_SERIALIZE_MAP() +}; + +struct ObjWithOptChild +{ + bool test_value; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_OPT(test_value, true); + END_KV_SERIALIZE_MAP() +}; +} + +TEST(epee_binary, serialize_deserialize) +{ + ParentObjWithOptChild<ObjWithOptChild> o; + std::string o_json; + o.params.test_value = true; + + EXPECT_TRUE(epee::serialization::store_t_to_json(o, o_json)); + EXPECT_TRUE(o.params.test_value); + + EXPECT_TRUE(epee::serialization::load_t_from_json(o, o_json)); + EXPECT_TRUE(o.params.test_value); + + ParentObjWithOptChild<ObjWithOptChild> o2; + std::string o2_json; + o.params.test_value = false; + + EXPECT_TRUE(epee::serialization::store_t_to_json(o2, o2_json)); + EXPECT_FALSE(o2.params.test_value); + + EXPECT_TRUE(epee::serialization::load_t_from_json(o2, o2_json)); + EXPECT_FALSE(o2.params.test_value); + + // compiler sets default value of test_value to false + ParentObjWithOptChild<ObjWithOptChild> o3; + std::string o3_json; + + EXPECT_TRUE(epee::serialization::store_t_to_json(o3, o3_json)); + EXPECT_FALSE(o3.params.test_value); + + EXPECT_TRUE(epee::serialization::load_t_from_json(o3, o3_json)); + EXPECT_FALSE(o3.params.test_value); + + // test optional field default initialization. + ParentObjWithOptChild<ObjWithOptChild> o4; + std::string o4_json = "{\"params\": {}}"; + + EXPECT_TRUE(epee::serialization::load_t_from_json(o4, o4_json)); + EXPECT_TRUE(o4.params.test_value); +} diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index d30bd3bd6..cc32f8bf3 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -1427,6 +1427,21 @@ TEST(StringTools, GetIpInt32) EXPECT_EQ(htonl(0xff0aff00), ip); } +TEST(StringTools, GetExtension) +{ + EXPECT_EQ(std::string{}, epee::string_tools::get_extension("")); + EXPECT_EQ(std::string{}, epee::string_tools::get_extension(".")); + EXPECT_EQ(std::string{"keys"}, epee::string_tools::get_extension("wallet.keys")); + EXPECT_EQ(std::string{"3"}, epee::string_tools::get_extension("1.2.3")); +} + +TEST(StringTools, CutOffExtension) +{ + EXPECT_EQ(std::string{}, epee::string_tools::cut_off_extension("")); + EXPECT_EQ(std::string{"/home/user/Monero/wallets/wallet"}, epee::string_tools::cut_off_extension("/home/user/Monero/wallets/wallet")); + EXPECT_EQ(std::string{"/home/user/Monero/wallets/wallet"}, epee::string_tools::cut_off_extension("/home/user/Monero/wallets/wallet.keys")); +} + TEST(NetUtils, IPv4NetworkAddress) { static_assert(epee::net_utils::ipv4_network_address::get_type_id() == epee::net_utils::address_type::ipv4, "bad ipv4 type id"); diff --git a/tests/unit_tests/is_hdd.cpp b/tests/unit_tests/is_hdd.cpp index 040af4f47..55f759ed9 100644 --- a/tests/unit_tests/is_hdd.cpp +++ b/tests/unit_tests/is_hdd.cpp @@ -1,17 +1,36 @@ #include "common/util.h" +#include <cstdlib> #include <string> #include <gtest/gtest.h> +#include <boost/optional/optional_io.hpp> /* required to output boost::optional in assertions */ + +#ifndef GTEST_SKIP +#include <iostream> +#define SKIP_TEST(reason) do {std::cerr << "Skipping test: " << reason << std::endl; return;} while(0) +#else +#define SKIP_TEST(reason) GTEST_SKIP() << reason +#endif #if defined(__GLIBC__) -TEST(is_hdd, linux_os_root) -{ - std::string path = "/"; - EXPECT_TRUE(tools::is_hdd(path.c_str()) != boost::none); +TEST(is_hdd, rotational_drive) { + const char *hdd = std::getenv("MONERO_TEST_DEVICE_HDD"); + if (hdd == nullptr) + SKIP_TEST("No rotational disk device configured"); + EXPECT_EQ(tools::is_hdd(hdd), boost::optional<bool>(true)); } -#else -TEST(is_hdd, unknown_os) -{ - std::string path = ""; - EXPECT_FALSE(tools::is_hdd(path.c_str()) != boost::none); + +TEST(is_hdd, ssd) { + const char *ssd = std::getenv("MONERO_TEST_DEVICE_SSD"); + if (ssd == nullptr) + SKIP_TEST("No SSD device configured"); + EXPECT_EQ(tools::is_hdd(ssd), boost::optional<bool>(false)); +} + +TEST(is_hdd, unknown_attrs) { + EXPECT_EQ(tools::is_hdd("/dev/null"), boost::none); } #endif +TEST(is_hdd, stability) +{ + EXPECT_NO_THROW(tools::is_hdd("")); +} diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp index 9525d23ea..9ac019aec 100644 --- a/tests/unit_tests/json_serialization.cpp +++ b/tests/unit_tests/json_serialization.cpp @@ -124,6 +124,68 @@ TEST(JsonSerialization, InvalidVectorBytes) EXPECT_THROW(cryptonote::json::fromJsonValue(doc, out), cryptonote::json::BAD_INPUT); } +TEST(JsonSerialization, DaemonInfo) +{ + cryptonote::rpc::DaemonInfo info{}; + info.height = 154544; + info.target_height = 15345435; + info.top_block_height = 2344; + info.wide_difficulty = cryptonote::difficulty_type{"100000000000000000005443"}; + info.difficulty = 200376420520695107; + info.target = 7657567; + info.tx_count = 355; + info.tx_pool_size = 45435; + info.alt_blocks_count = 43535; + info.outgoing_connections_count = 1444; + info.incoming_connections_count = 1444; + info.white_peerlist_size = 14550; + info.grey_peerlist_size = 34324; + info.mainnet = true; + info.testnet = true; + info.stagenet = true; + info.nettype = "main"; + info.top_block_hash = crypto::hash{1}; + info.wide_cumulative_difficulty = cryptonote::difficulty_type{"200000000000000000005543"}; + info.cumulative_difficulty = 400752841041384871; + info.block_size_limit = 4324234; + info.block_weight_limit = 3434; + info.block_size_median = 3434; + info.adjusted_time = 4535; + info.block_weight_median = 43535; + info.start_time = 34535; + info.version = "1.0"; + + const auto info_copy = test_json(info); + + EXPECT_EQ(info.height, info_copy.height); + EXPECT_EQ(info.target_height, info_copy.target_height); + EXPECT_EQ(info.top_block_height, info_copy.top_block_height); + EXPECT_EQ(info.wide_difficulty, info_copy.wide_difficulty); + EXPECT_EQ(info.difficulty, info_copy.difficulty); + EXPECT_EQ(info.target, info_copy.target); + EXPECT_EQ(info.tx_count, info_copy.tx_count); + EXPECT_EQ(info.tx_pool_size, info_copy.tx_pool_size); + EXPECT_EQ(info.alt_blocks_count, info_copy.alt_blocks_count); + EXPECT_EQ(info.outgoing_connections_count, info_copy.outgoing_connections_count); + EXPECT_EQ(info.incoming_connections_count, info_copy.incoming_connections_count); + EXPECT_EQ(info.white_peerlist_size, info_copy.white_peerlist_size); + EXPECT_EQ(info.grey_peerlist_size, info_copy.grey_peerlist_size); + EXPECT_EQ(info.mainnet, info_copy.mainnet); + EXPECT_EQ(info.testnet, info_copy.testnet); + EXPECT_EQ(info.stagenet, info_copy.stagenet); + EXPECT_EQ(info.nettype, info_copy.nettype); + EXPECT_EQ(info.top_block_hash, info_copy.top_block_hash); + EXPECT_EQ(info.wide_cumulative_difficulty, info_copy.wide_cumulative_difficulty); + EXPECT_EQ(info.cumulative_difficulty, info_copy.cumulative_difficulty); + EXPECT_EQ(info.block_size_limit, info_copy.block_size_limit); + EXPECT_EQ(info.block_weight_limit, info_copy.block_weight_limit); + EXPECT_EQ(info.block_size_median, info_copy.block_size_median); + EXPECT_EQ(info.adjusted_time, info_copy.adjusted_time); + EXPECT_EQ(info.block_weight_median, info_copy.block_weight_median); + EXPECT_EQ(info.start_time, info_copy.start_time); + EXPECT_EQ(info.version, info_copy.version); +} + TEST(JsonSerialization, MinerTransaction) { cryptonote::account_base acct; diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp index 103bac08f..6eac92de7 100644 --- a/tests/unit_tests/levin.cpp +++ b/tests/unit_tests/levin.cpp @@ -2219,6 +2219,63 @@ TEST_F(levin_notify, fluff_multiple) } } +TEST_F(levin_notify, fluff_with_duplicate) +{ + std::shared_ptr<cryptonote::levin::notify> notifier_ptr = make_notifier(0, true, false); + auto ¬ifier = *notifier_ptr; + + for (unsigned count = 0; count < 10; ++count) + add_connection(count % 2 == 0); + + { + const auto status = notifier.get_status(); + EXPECT_FALSE(status.has_noise); + EXPECT_FALSE(status.connections_filled); + EXPECT_TRUE(status.has_outgoing); + } + notifier.new_out_connection(); + io_service_.poll(); + + std::vector<cryptonote::blobdata> txs(9); + txs[0].resize(100, 'e'); + txs[1].resize(100, 'e'); + txs[2].resize(100, 'e'); + txs[3].resize(100, 'e'); + txs[4].resize(200, 'f'); + txs[5].resize(200, 'f'); + txs[6].resize(200, 'f'); + txs[7].resize(200, 'f'); + txs[8].resize(200, 'f'); + + ASSERT_EQ(10u, contexts_.size()); + { + auto context = contexts_.begin(); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff)); + + io_service_.reset(); + ASSERT_LT(0u, io_service_.poll()); + notifier.run_fluff(); + ASSERT_LT(0u, io_service_.poll()); + + EXPECT_EQ(0u, context->process_send_queue()); + for (++context; context != contexts_.end(); ++context) + EXPECT_EQ(1u, context->process_send_queue()); + + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff)); + std::sort(txs.begin(), txs.end()); + ASSERT_EQ(9u, receiver_.notified_size()); + for (unsigned count = 0; count < 9; ++count) + { + auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second; + EXPECT_NE(txs, notification.txs); + EXPECT_EQ(notification.txs.size(), 2); + EXPECT_TRUE(notification._.empty()); + EXPECT_TRUE(notification.dandelionpp_fluff); + } + } + +} + TEST_F(levin_notify, noise) { for (unsigned count = 0; count < 10; ++count) diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index 3b3c4197c..71416aaf3 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -80,7 +80,7 @@ static void make_wallet(unsigned int idx, tools::wallet2 &wallet) wallet.generate("", "", spendkey, true, false); ASSERT_TRUE(test_addresses[idx].address == wallet.get_account().get_public_address_str(cryptonote::TESTNET)); wallet.decrypt_keys(""); - ASSERT_TRUE(test_addresses[idx].spendkey == epee::string_tools::pod_to_hex(wallet.get_account().get_keys().m_spend_secret_key)); + ASSERT_TRUE(test_addresses[idx].spendkey == epee::string_tools::pod_to_hex(unwrap(unwrap(wallet.get_account().get_keys().m_spend_secret_key)))); wallet.encrypt_keys(""); } catch (const std::exception &e) diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp index 584f98f7a..09b1d5461 100644 --- a/tests/unit_tests/node_server.cpp +++ b/tests/unit_tests/node_server.cpp @@ -35,6 +35,7 @@ #include "cryptonote_core/i_core_events.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.inl" +#include "unit_tests_utils.h" #include <condition_variable> #define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0} @@ -114,6 +115,18 @@ static bool is_blocked(Server &server, const epee::net_utils::network_address &a return true; } } + + if (address.get_type_id() != epee::net_utils::address_type::ipv4) + return false; + + const epee::net_utils::ipv4_network_address ipv4_address = address.as<epee::net_utils::ipv4_network_address>(); + + // check if in a blocked ipv4 subnet + const std::map<epee::net_utils::ipv4_network_subnet, time_t> subnets = server.get_blocked_subnets(); + for (const auto &subnet : subnets) + if (subnet.first.matches(ipv4_address)) + return true; + return false; } @@ -224,6 +237,18 @@ TEST(ban, subnet) test_core pr_core; cryptonote::t_cryptonote_protocol_handler<test_core> cprotocol(pr_core, NULL); Server server(cprotocol); + { + boost::program_options::options_description opts{}; + Server::init_options(opts); + cryptonote::core::init_options(opts); + + char** args = nullptr; + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line(0, args, opts), vm + ); + server.init(vm); + } cprotocol.set_p2p_endpoint(&server); ASSERT_TRUE(server.block_subnet(MAKE_IPV4_SUBNET(1,2,3,4,24), 10)); @@ -266,6 +291,78 @@ TEST(ban, ignores_port) ASSERT_FALSE(is_blocked(server,MAKE_IPV4_ADDRESS_PORT(1,2,3,4,6))); } +TEST(ban, file_banlist) +{ + test_core pr_core; + cryptonote::t_cryptonote_protocol_handler<test_core> cprotocol(pr_core, NULL); + Server server(cprotocol); + cprotocol.set_p2p_endpoint(&server); + + auto create_node_dir = [](){ + boost::system::error_code ec; + auto path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("daemon-%%%%%%%%%%%%%%%%", ec); + if (ec) + return boost::filesystem::path{}; + auto success = boost::filesystem::create_directory(path, ec); + if (!ec && success) + return path; + return boost::filesystem::path{}; + }; + const auto node_dir = create_node_dir(); + ASSERT_TRUE(!node_dir.empty()); + auto auto_remove_node_dir = epee::misc_utils::create_scope_leave_handler([&node_dir](){ + boost::filesystem::remove_all(node_dir); + }); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::command_line_parser({ + "--data-dir", + node_dir.string(), + "--ban-list", + (unit_test::data_dir / "node" / "banlist_1.txt").string() + }).options([]{ + boost::program_options::options_description options_description{}; + cryptonote::core::init_options(options_description); + Server::init_options(options_description); + return options_description; + }()).run(), + vm + ); + + ASSERT_TRUE(server.init(vm)); + + // Test cases (look in the banlist_1.txt file) + + // magicfolk + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(255,255,255,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(128,128,128,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(150,75,0,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,0,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,0,255,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,98,255,255,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(99,99,0,0,9999)) ); + + // personal enemies + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,2,3,4,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(6,7,8,9,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,0,0,7,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(1,0,0,7,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,13,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,0,9999)) ); + EXPECT_TRUE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,1,255,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,2,0,9999)) ); + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(100,98,0,255,9999)) ); + + // angel + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(007,007,007,007,9999)) ); + + // random IP + EXPECT_FALSE( is_blocked(server, MAKE_IPV4_ADDRESS_PORT(145,036,205,235,9999)) ); +} + TEST(node_server, bind_same_p2p_port) { struct test_data_t diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 0fdd83285..fdf603272 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -1103,7 +1103,7 @@ TEST(Serialization, portability_signed_tx) ASSERT_TRUE(ptx.selected_transfers.front() == 2); // ptx.{key_images, tx_key} ASSERT_TRUE(ptx.key_images == "<6c3cd6af97c4070a7aef9b1344e7463e29c7cd245076fdb65da447a34da3ca76> "); - ASSERT_TRUE(epee::string_tools::pod_to_hex(ptx.tx_key) == "0100000000000000000000000000000000000000000000000000000000000000"); + ASSERT_TRUE(epee::string_tools::pod_to_hex(unwrap(unwrap(ptx.tx_key))) == "0100000000000000000000000000000000000000000000000000000000000000"); // ptx.dests ASSERT_TRUE(ptx.dests.size() == 1); ASSERT_TRUE(ptx.dests[0].amount == 1400000000000); diff --git a/utils/fish/monerod.fish b/utils/fish/monerod.fish index d2836a6b2..04003f0ff 100644 --- a/utils/fish/monerod.fish +++ b/utils/fish/monerod.fish @@ -79,8 +79,8 @@ complete -c monerod -l igd -r -a "Enabled disabled enabled" -d "UPnP port mappin complete -c monerod -l out-peers -r -d "Set max number of out peers. Default: -1" complete -c monerod -l in-peers -r -d "Set max number of in peers. Default: -1" complete -c monerod -l tos-flag -r -d "Set TOS flag. Default: -1" -complete -c monerod -l limit-rate-up -r -d "Set limit-rate-up [kB/s]. Default: 2048" -complete -c monerod -l limit-rate-down -r -d "Set limit-rate-down [kB/s]. Default: 8192" +complete -c monerod -l limit-rate-up -r -d "Set limit-rate-up [kB/s]. Default: 8192" +complete -c monerod -l limit-rate-down -r -d "Set limit-rate-down [kB/s]. Default: 32768" complete -c monerod -l limit-rate -r -d "Set limit-rate [kB/s]. Default: -1" complete -c monerod -l pad-transactions -d "Pad relayed transactions to help defend against traffic volume analysis" complete -c monerod -l max-connections-per-ip -r -d "Maximum number of connections allowed from the same IP address. Default: 1" diff --git a/utils/systemd/monerod.service b/utils/systemd/monerod.service index 63daefa82..28b457d56 100644 --- a/utils/systemd/monerod.service +++ b/utils/systemd/monerod.service @@ -1,6 +1,6 @@ [Unit] Description=Monero Full Node -After=network.target +After=network-online.target [Service] User=monero |
