diff options
84 files changed, 1289 insertions, 581 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bc1d6498..806c8a0fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,8 @@ jobs: - uses: actions/checkout@v1 with: submodules: recursive - - name: update brew and install dependencies - run: brew update && brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf + - name: install dependencies + run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi zmq libpgm miniupnpc ldns expat libunwind-headers protobuf - name: build run: make -j3 @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v1 with: submodules: recursive - - uses: eine/setup-msys2@v1 + - uses: eine/setup-msys2@v2 with: update: true install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake 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 git diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a16e0081..050269218 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,20 @@ else() message(STATUS "ccache deselected") endif() +if (${CMAKE_VERSION} VERSION_GREATER "3.0.0" AND CMAKE_MAKE_PROGRAM MATCHES "ninja") + set(MONERO_PARALLEL_COMPILE_JOBS "" CACHE STRING "The maximum number of concurrent compilation jobs.") + if (MONERO_PARALLEL_COMPILE_JOBS) + set_property(GLOBAL APPEND PROPERTY JOB_POOLS compile_job_pool=${MONERO_PARALLEL_COMPILE_JOBS}) + set(CMAKE_JOB_POOL_COMPILE compile_job_pool) + endif () + + set(MONERO_PARALLEL_LINK_JOBS "" CACHE STRING "The maximum number of concurrent link jobs.") + if (MONERO_PARALLEL_LINK_JOBS) + set_property(GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${MONERO_PARALLEL_LINK_JOBS}) + set(CMAKE_JOB_POOL_LINK link_job_pool) + endif () +endif() + enable_language(C ASM) function (die msg) @@ -111,6 +125,24 @@ function (add_definition_if_library_exists library function header var) endif() endfunction() +option(RELINK_TARGETS "Relink targets, when just a dependant .so changed, but not its header?" OFF) +function (monero_set_target_no_relink target) + if (RELINK_TARGETS MATCHES OFF) + # Will not relink the target, when just its dependant .so has changed, but not it's interface + set_target_properties("${target}" PROPERTIES LINK_DEPENDS_NO_SHARED true) + endif() +endfunction() + +function (monero_add_minimal_executable name) + source_group("${name}" + FILES + ${ARGN}) + + add_executable("${name}" + ${ARGN}) + monero_set_target_no_relink( ${name} ) +endfunction() + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}") @@ -395,7 +427,7 @@ elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) set(DEFAULT_STACK_TRACE ON) set(STACK_TRACE_LIB "easylogging++") # for diag output only set(LIBUNWIND_LIBRARIES "") -elseif (ARM AND STATIC) +elseif (ARM) set(DEFAULT_STACK_TRACE OFF) set(LIBUNWIND_LIBRARIES "") else() @@ -969,6 +1001,7 @@ find_path(ZMQ_INCLUDE_PATH zmq.h) find_library(ZMQ_LIB zmq) find_library(PGM_LIBRARY pgm) find_library(NORM_LIBRARY norm) +find_library(GSSAPI_LIBRARY gssapi_krb5) find_library(PROTOLIB_LIBRARY protolib) find_library(SODIUM_LIBRARY sodium) @@ -984,6 +1017,9 @@ endif() if(NORM_LIBRARY) set(ZMQ_LIB "${ZMQ_LIB};${NORM_LIBRARY}") endif() +if(GSSAPI_LIBRARY) + set(ZMQ_LIB "${ZMQ_LIB};${GSSAPI_LIBRARY}") +endif() if(PROTOLIB_LIBRARY) set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}") endif() @@ -64,6 +64,7 @@ If you need help/support/info about translations, contact the localization workg | Type | Status | |-----------|--------| | Coverity | [![Coverity Status](https://scan.coverity.com/projects/9657/badge.svg)](https://scan.coverity.com/projects/9657/) +| OSS Fuzz | [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/monero.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:monero) | Coveralls | [![Coveralls Status](https://coveralls.io/repos/github/monero-project/monero/badge.svg?branch=master)](https://coveralls.io/github/monero-project/monero?branch=master) | License | [![License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) @@ -71,9 +72,9 @@ If you need help/support/info about translations, contact the localization workg Monero is a private, secure, untraceable, decentralised digital currency. You are your bank, you control your funds, and nobody can trace your transfers unless you allow them to do so. -**Privacy:** Monero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain absolutely private by default. +**Privacy:** Monero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain private by default. -**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25-word mnemonic seed that is only displayed once and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen. +**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25-word mnemonic seed that is only displayed once and can be written down to backup the wallet. Wallet files should be encrypted with a strong passphrase to ensure they are useless if ever stolen. **Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Monero is able to ensure that transactions are not only untraceable but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer. @@ -95,15 +96,13 @@ The Monero donation address is: `888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnj The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H` -Core development funding and/or some supporting services are also graciously provided by sponsors: +Core development funding and/or some supporting services are also graciously provided by [sponsors](https://www.getmonero.org/community/sponsorships/): -[<img width="80" src="https://static.getmonero.org/images/sponsors/mymonero.png"/>](https://mymonero.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/kitware.png?1"/>](https://kitware.com) -[<img width="100" src="https://static.getmonero.org/images/sponsors/dome9.png"/>](https://dome9.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/araxis.png"/>](https://araxis.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/jetbrains.png"/>](https://www.jetbrains.com/) -[<img width="150" src="https://static.getmonero.org/images/sponsors/navicat.png"/>](https://www.navicat.com/) -[<img width="150" src="https://static.getmonero.org/images/sponsors/symas.png"/>](https://www.symas.com/) +[<img width="150" src="https://www.getmonero.org/img/sponsors/tarilabs.png"/>](https://tarilabs.com/) +[<img width="150" src="https://www.getmonero.org/img/sponsors/globee.png"/>](https://globee.com/) +[<img width="150" src="https://www.getmonero.org/img/sponsors/symas.png"/>](https://symas.com/) +[<img width="150" src="https://www.getmonero.org/img/sponsors/forked_logo.png"/>](http://www.forked.net/) +[<img width="150" src="https://www.getmonero.org/img/sponsors/macstadium.png"/>](https://www.macstadium.com/) There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0). @@ -113,7 +112,7 @@ See [LICENSE](LICENSE). ## Contributing -If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidelines. +If you want to help out, see [CONTRIBUTING](docs/CONTRIBUTING.md) for a set of guidelines. ## Scheduled software upgrades @@ -134,8 +133,8 @@ Dates are provided in the format YYYY-MM-DD. | 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format | 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format | 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.0.0 | New CLSAG transaction format -| 2210720 | 2020-10-18 | v14 | v0.17.0.0 | v0.17.0.0 | forbid old MLSAG transaction format +| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.1 | New CLSAG transaction format +| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.1 | forbid old MLSAG 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. @@ -295,7 +294,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 tags/v0.17.0.0 + git checkout tags/v0.17.1.0 ``` * Build: @@ -412,10 +411,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.17.0.0'. 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.17.1.0'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.17.0.0 + git checkout v0.17.1.0 ``` * If you are on a 64-bit system, run: @@ -650,11 +649,11 @@ monero-wallet-cli, and possibly monerod, if you get crashes refreshing. ## Internationalization -See [README.i18n.md](README.i18n.md). +See [README.i18n.md](docs/README.i18n.md). ## Using Tor -> There is a new, still experimental, [integration with Tor](ANONYMITY_NETWORKS.md). The +> There is a new, still experimental, [integration with Tor](docs/ANONYMITY_NETWORKS.md). The > feature allows connecting over IPv4 and Tor simultaneously - IPv4 is used for > relaying blocks and relaying transactions received by peers whereas Tor is > used solely for relaying transactions received over local RPC. This provides diff --git a/cmake/CheckTrezor.cmake b/cmake/CheckTrezor.cmake index d2fe60d92..f600cc0bb 100644 --- a/cmake/CheckTrezor.cmake +++ b/cmake/CheckTrezor.cmake @@ -91,7 +91,7 @@ endif() # Protobuf compilation test if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON) - execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_SOURCE_DIR}/cmake" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR) + execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_CURRENT_LIST_DIR}" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_CURRENT_LIST_DIR}/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR) if(RET) message(STATUS "Protobuf test generation failed: ${OUT} ${ERR}") endif() @@ -100,7 +100,7 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON) "${CMAKE_BINARY_DIR}" SOURCES "${CMAKE_BINARY_DIR}/test-protobuf.pb.cc" - "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test-protobuf.cpp" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}" "-DCMAKE_CXX_STANDARD=11" diff --git a/cmake/Version.cmake b/cmake/Version.cmake index a6c13ab6c..707d72639 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -28,7 +28,7 @@ function (write_version tag) set(VERSIONTAG "${tag}" CACHE STRING "The tag portion of the Monero software version" FORCE) - configure_file("${CMAKE_SOURCE_DIR}/src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp") + configure_file("${CMAKE_CURRENT_LIST_DIR}/../src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp") endfunction () find_package(Git QUIET) diff --git a/contrib/depends/packages/qt.mk b/contrib/depends/packages/qt.mk index 98cef4631..76c50f3fd 100644 --- a/contrib/depends/packages/qt.mk +++ b/contrib/depends/packages/qt.mk @@ -1,18 +1,18 @@ PACKAGE=qt -$(package)_version=5.7.1 -$(package)_download_path=http://linorg.usp.br/Qt/archive/qt/5.7/5.7.1/submodules -$(package)_suffix=opensource-src-$($(package)_version).tar.gz +$(package)_version=5.15.1 +$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules +$(package)_suffix=everywhere-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 +$(package)_sha256_hash=33960404d579675b7210de103ed06a72613bfc4305443e278e2d32a3eb1f3d8c $(package)_build_subdir=qtbase $(package)_qt_libs=corelib -$(package)_patches=pidlist_absolute.patch fix_qt_pkgconfig.patch qfixed-coretext.patch +$(package)_patches=fix_qt_pkgconfig.patch fix_no_printer.patch fix_rcc_determinism.patch no-xlib.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d +$(package)_qttranslations_sha256_hash=46e0c0e3a511fbcc803a4146204062e47f6ed43b34d98a3c27372a03b8746bd8 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f +$(package)_qttools_sha256_hash=c98ee5f0f980bf68cbf0c94d62434816a92441733de50bd9adbe9b9055f03498 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) @@ -24,28 +24,26 @@ $(package)_config_opts += -bindir $(build_prefix)/bin $(package)_config_opts += -c++std c++11 $(package)_config_opts += -confirm-license $(package)_config_opts += -dbus-runtime -$(package)_config_opts += -no-alsa -$(package)_config_opts += -no-audio-backend +$(package)_config_opts += -hostprefix $(build_prefix) +$(package)_config_opts += -no-compile-examples $(package)_config_opts += -no-cups $(package)_config_opts += -no-egl $(package)_config_opts += -no-eglfs -$(package)_config_opts += -no-feature-style-windowsmobile -$(package)_config_opts += -no-feature-style-windowsce +$(package)_config_opts += -no-evdev +$(package)_config_opts += -no-gui $(package)_config_opts += -no-freetype $(package)_config_opts += -no-gif $(package)_config_opts += -no-glib -$(package)_config_opts += -no-gstreamer $(package)_config_opts += -no-icu +$(package)_config_opts += -no-ico $(package)_config_opts += -no-iconv $(package)_config_opts += -no-kms $(package)_config_opts += -no-linuxfb +$(package)_config_opts += -no-libjpeg $(package)_config_opts += -no-libudev -$(package)_config_opts += -no-mitshm $(package)_config_opts += -no-mtdev -$(package)_config_opts += -no-pulseaudio $(package)_config_opts += -no-openvg $(package)_config_opts += -no-reduce-relocations -$(package)_config_opts += -no-qml-debug $(package)_config_opts += -no-sql-db2 $(package)_config_opts += -no-sql-ibase $(package)_config_opts += -no-sql-oci @@ -56,8 +54,6 @@ $(package)_config_opts += -no-sql-psql $(package)_config_opts += -no-sql-sqlite $(package)_config_opts += -no-sql-sqlite2 $(package)_config_opts += -no-use-gold-linker -$(package)_config_opts += -no-xinput2 -$(package)_config_opts += -no-xrender $(package)_config_opts += -nomake examples $(package)_config_opts += -nomake tests $(package)_config_opts += -opensource @@ -65,25 +61,46 @@ $(package)_config_opts += -no-openssl $(package)_config_opts += -optimized-qmake $(package)_config_opts += -pch $(package)_config_opts += -pkg-config +$(package)_config_opts += -prefix $(host_prefix) $(package)_config_opts += -no-libpng -$(package)_config_opts += -no-libjpeg $(package)_config_opts += -qt-pcre +$(package)_config_opts += -qt-harfbuzz $(package)_config_opts += -no-zlib -$(package)_config_opts += -reduce-exports $(package)_config_opts += -static $(package)_config_opts += -silent $(package)_config_opts += -v -$(package)_config_opts += -no-feature-printer +$(package)_config_opts += -no-feature-bearermanagement +$(package)_config_opts += -no-feature-colordialog +$(package)_config_opts += -no-feature-dial +$(package)_config_opts += -no-feature-filesystemwatcher +$(package)_config_opts += -no-feature-fontcombobox +$(package)_config_opts += -no-feature-ftp +$(package)_config_opts += -no-feature-image_heuristic_mask +$(package)_config_opts += -no-feature-keysequenceedit +$(package)_config_opts += -no-feature-lcdnumber +$(package)_config_opts += -no-feature-pdf $(package)_config_opts += -no-feature-printdialog -$(package)_config_opts += -no-gui -$(package)_config_opts += -no-freetype -$(package)_config_opts += -no-sm -$(package)_config_opts += -no-fontconfig -$(package)_config_opts += -no-opengl -$(package)_config_opts += -no-xkb -$(package)_config_opts += -no-xcb -$(package)_config_opts += -no-xshape -$(package)_build_env = QT_RCC_TEST=1 +$(package)_config_opts += -no-feature-printer +$(package)_config_opts += -no-feature-printpreviewdialog +$(package)_config_opts += -no-feature-printpreviewwidget +$(package)_config_opts += -no-feature-sessionmanager +$(package)_config_opts += -no-feature-sql +$(package)_config_opts += -no-feature-statemachine +$(package)_config_opts += -no-feature-syntaxhighlighter +$(package)_config_opts += -no-feature-textbrowser +$(package)_config_opts += -no-feature-textodfwriter +$(package)_config_opts += -no-feature-topleveldomain +$(package)_config_opts += -no-feature-udpsocket +$(package)_config_opts += -no-feature-undocommand +$(package)_config_opts += -no-feature-undogroup +$(package)_config_opts += -no-feature-undostack +$(package)_config_opts += -no-feature-undoview +$(package)_config_opts += -no-feature-vnc +$(package)_config_opts += -no-feature-wizard +$(package)_config_opts_linux = -no-fontconfig +$(package)_config_opts_linux += -no-opengl +$(package)_config_opts_linux += -no-xcb +$(package)_config_opts_linux += -no-feature-xlib endef define $(package)_fetch_cmds @@ -108,14 +125,24 @@ endef define $(package)_preprocess_cmds + sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ - patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ - patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ - patch -p1 < $($(package)_patch_dir)/qfixed-coretext.patch && \ + sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ + cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \ + sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ - echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf + echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ + echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf && \ + echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf endef define $(package)_config_cmds diff --git a/contrib/depends/patches/qt/fix_no_printer.patch b/contrib/depends/patches/qt/fix_no_printer.patch new file mode 100644 index 000000000..137235613 --- /dev/null +++ b/contrib/depends/patches/qt/fix_no_printer.patch @@ -0,0 +1,19 @@ +--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h ++++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h +@@ -52,6 +52,7 @@ + // + + #include <QtCore/qglobal.h> ++#include <qpa/qplatformprintdevice.h> + + #ifndef QT_NO_PRINTER + +--- x/qtbase/src/plugins/plugins.pro ++++ y/qtbase/src/plugins/plugins.pro +@@ -9,6 +9,3 @@ qtHaveModule(gui) { + !android:qtConfig(library): SUBDIRS *= generic + } + qtHaveModule(widgets): SUBDIRS += styles +- +-!winrt:qtHaveModule(printsupport): \ +- SUBDIRS += printsupport diff --git a/contrib/depends/patches/qt/fix_qt_pkgconfig.patch b/contrib/depends/patches/qt/fix_qt_pkgconfig.patch index 34302a9f2..73f4d89f7 100644 --- a/contrib/depends/patches/qt/fix_qt_pkgconfig.patch +++ b/contrib/depends/patches/qt/fix_qt_pkgconfig.patch @@ -1,11 +1,11 @@ --- old/qtbase/mkspecs/features/qt_module.prf +++ new/qtbase/mkspecs/features/qt_module.prf -@@ -245,7 +245,7 @@ +@@ -269,7 +269,7 @@ load(qt_installs) load(qt_targets) # this builds on top of qt_common --!internal_module:!lib_bundle:if(unix|mingw) { -+unix|mingw { +-!internal_module:if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) { ++if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) { CONFIG += create_pc QMAKE_PKGCONFIG_DESTDIR = pkgconfig host_build: \ diff --git a/contrib/depends/patches/qt/fix_rcc_determinism.patch b/contrib/depends/patches/qt/fix_rcc_determinism.patch new file mode 100644 index 000000000..c1b07fe23 --- /dev/null +++ b/contrib/depends/patches/qt/fix_rcc_determinism.patch @@ -0,0 +1,15 @@ +--- old/qtbase/src/tools/rcc/rcc.cpp ++++ new/qtbase/src/tools/rcc/rcc.cpp +@@ -207,7 +207,11 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) + if (lib.formatVersion() >= 2) { + // last modified time stamp + const QDateTime lastModified = m_fileInfo.lastModified(); +- lib.writeNumber8(quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0)); ++ quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0); ++ static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong(); ++ if (sourceDate != 0) ++ lastmod = sourceDate; ++ lib.writeNumber8(lastmod); + if (text || pass1) + lib.writeChar('\n'); + } diff --git a/contrib/depends/patches/qt/no-xlib.patch b/contrib/depends/patches/qt/no-xlib.patch new file mode 100644 index 000000000..6800d398c --- /dev/null +++ b/contrib/depends/patches/qt/no-xlib.patch @@ -0,0 +1,69 @@ +From 9563cef873ae82e06f60708d706d054717e801ce Mon Sep 17 00:00:00 2001 +From: Carl Dong <contact@carldong.me> +Date: Thu, 18 Jul 2019 17:22:05 -0400 +Subject: [PATCH] Wrap xlib related code blocks in #if's + +They are not necessary to compile QT. +--- + qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +index 7c62c2e2b3..c05c6c0a07 100644 +--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp ++++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +@@ -49,7 +49,9 @@ + #include <QtGui/QWindow> + #include <QtGui/QBitmap> + #include <QtGui/private/qguiapplication_p.h> ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + #include <X11/cursorfont.h> ++#endif + #include <xcb/xfixes.h> + #include <xcb/xcb_image.h> + +@@ -391,6 +393,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window) + xcb_flush(xcb_connection()); + } + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + static int cursorIdForShape(int cshape) + { + int cursorId = 0; +@@ -444,6 +447,7 @@ static int cursorIdForShape(int cshape) + } + return cursorId; + } ++#endif + + xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) + { +@@ -556,7 +560,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) + xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + { + xcb_connection_t *conn = xcb_connection(); ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + int cursorId = cursorIdForShape(cshape); ++#endif + xcb_cursor_t cursor = XCB_NONE; + + // Try Xcursor first +@@ -586,6 +592,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + // Non-standard X11 cursors are created from bitmaps + cursor = createNonStandardCursor(cshape); + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + // Create a glpyh cursor if everything else failed + if (!cursor && cursorId) { + cursor = xcb_generate_id(conn); +@@ -593,6 +600,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + cursorId, cursorId + 1, + 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); + } ++#endif + + if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) { + const char *name = cursorNames[cshape].front(); +--- +2.22.0 + diff --git a/contrib/depends/patches/qt/pidlist_absolute.patch b/contrib/depends/patches/qt/pidlist_absolute.patch deleted file mode 100644 index c79282417..000000000 --- a/contrib/depends/patches/qt/pidlist_absolute.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h ---- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h -+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h -@@ -136,10 +136,18 @@ - inline void init(); - - typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **); -+#else - typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *); -+#endif - typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); - typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **); -+#else - typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **); -+#endif - - SHCreateItemFromParsingName sHCreateItemFromParsingName; - SHGetKnownFolderIDList sHGetKnownFolderIDList; -diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp ---- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -+++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp -@@ -1016,7 +1016,11 @@ - qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path(); - return Q_NULLPTR; - } -+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) -+ ITEMIDLIST *idList; -+#else - PIDLIST_ABSOLUTE idList; -+#endif - HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList); - if (FAILED(hr)) { - qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); diff --git a/contrib/depends/patches/qt/qfixed-coretext.patch b/contrib/depends/patches/qt/qfixed-coretext.patch deleted file mode 100644 index aa56f1e1d..000000000 --- a/contrib/depends/patches/qt/qfixed-coretext.patch +++ /dev/null @@ -1,34 +0,0 @@ -From dbdd5f0ffbce52c8b789ed09f1aa3f1da6c02e23 Mon Sep 17 00:00:00 2001 -From: Gabriel de Dietrich <gabriel.dedietrich@qt.io> -Date: Fri, 30 Mar 2018 11:58:16 -0700 -Subject: [PATCH] QCoreTextFontEngine: Fix build with Xcode 9.3 - -Apple LLVM version 9.1.0 (clang-902.0.39.1) - -Error message: - -.../qfontengine_coretext.mm:827:20: error: qualified reference to - 'QFixed' is a constructor name rather than a type in this context - return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); - -Change-Id: Iebe26b3b087a16b10664208fc8851cbddb47f043 -Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com> ---- - src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm -index 25ff69d877d..98b753eff96 100644 ---- old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm -+++ new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm -@@ -824,7 +824,7 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl - - QFixed QCoreTextFontEngine::emSquareSize() const - { -- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); -+ return QFixed(int(CTFontGetUnitsPerEm(ctfont))); - } - - QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const --- -2.16.3
\ No newline at end of file diff --git a/contrib/epee/include/net/net_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h index 1d156d19c..cf637ba1d 100644 --- a/contrib/epee/include/net/net_parse_helpers.h +++ b/contrib/epee/include/net/net_parse_helpers.h @@ -131,8 +131,8 @@ namespace net_utils inline bool parse_url_ipv6(const std::string url_str, http::url_content& content) { - STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(\\[(.*)\\](:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); - // 12 3 4 5 6 7 + STATIC_REGEXP_EXPR_1(rexp_match_uri, "^(([^:]*?)://)?(\\[(.*)\\](:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); + // 12 3 4 5 6 7 content.port = 0; boost::smatch result; @@ -175,8 +175,8 @@ namespace net_utils ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash= //STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal); - STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); - // 12 34 5 6 7 + STATIC_REGEXP_EXPR_1(rexp_match_uri, "^(([^:]*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal); + // 12 34 5 6 7 content.port = 0; boost::smatch result; if(!(boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched)) diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index 05322b693..bcf499963 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -51,6 +51,7 @@ rdln::readline_buffer::readline_buffer() void rdln::readline_buffer::start() { + boost::lock_guard<boost::mutex> lock(sync_mutex); if(m_cout_buf != NULL) return; m_cout_buf = std::cout.rdbuf(); @@ -60,6 +61,7 @@ void rdln::readline_buffer::start() void rdln::readline_buffer::stop() { + boost::lock_guard<boost::mutex> lock(sync_mutex); if(m_cout_buf == NULL) return; std::cout.rdbuf(m_cout_buf); @@ -88,9 +90,9 @@ rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const void rdln::readline_buffer::set_prompt(const std::string& prompt) { + boost::lock_guard<boost::mutex> lock(sync_mutex); if(m_cout_buf == NULL) return; - boost::lock_guard<boost::mutex> lock(sync_mutex); rl_set_prompt(std::string(m_prompt_length, ' ').c_str()); rl_redisplay(); rl_set_prompt(prompt.c_str()); @@ -113,6 +115,12 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions() int rdln::readline_buffer::sync() { boost::lock_guard<boost::mutex> lock(sync_mutex); + + if (m_cout_buf == nullptr) + { + return -1; + } + #if RL_READLINE_VERSION < 0x0700 char lbuf[2] = {0,0}; char *line = NULL; diff --git a/contrib/gitian/gitian-freebsd.yml b/contrib/gitian/gitian-freebsd.yml index c104bfd02..36b81c641 100644 --- a/contrib/gitian/gitian-freebsd.yml +++ b/contrib/gitian/gitian-freebsd.yml @@ -119,7 +119,7 @@ script: | for i in ${HOSTS}; do export PATH=${WRAP_DIR}:${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir build && cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DCMAKE_BUILD_TYPE=Release + cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=ON make ${MAKEOPTS} chmod 755 bin/* cp ../LICENSE bin diff --git a/contrib/gitian/gitian-linux.yml b/contrib/gitian/gitian-linux.yml index 4a2f3798a..0aac983cc 100644 --- a/contrib/gitian/gitian-linux.yml +++ b/contrib/gitian/gitian-linux.yml @@ -111,6 +111,11 @@ script: | rm -f $WRAP_DIR/extra_includes/i686-linux-gnu/asm ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-linux-gnu/asm + # glibc 2.23 breaks compatibility with <=2.19 use of lgamma function. + # Hack the math header to restore the old behavior. + mkdir $EXTRA_INCLUDES_BASE/bits + sed -e '/__REDIRFROM .lgamma,/,+3s/_USE_/_DONTUSE_/g' /usr/include/x86_64-linux-gnu/bits/math-finite.h > $EXTRA_INCLUDES_BASE/bits/math-finite.h + # gcc 7+ honors SOURCE_DATE_EPOCH, no faketime needed export SOURCE_DATE_EPOCH=`date -d 2000-01-01T12:00:00 +%s` @@ -127,14 +132,14 @@ script: | # Build dependencies for each host export TAR_OPTIONS=--mtime=2000-01-01T12:00:00 for i in $HOSTS; do - EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i" - if [ -d "$EXTRA_INCLUDES" ]; then - export C_INCLUDE_PATH="$EXTRA_INCLUDES" - export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES" + ARCH_INCLUDES="$EXTRA_INCLUDES_BASE/$i" + if [ -d "$ARCH_INCLUDES" ]; then + EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}:${ARCH_INCLUDES}" else - unset C_INCLUDE_PATH - unset CPLUS_INCLUDE_PATH + EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}" fi + export C_INCLUDE_PATH="$EXTRA_INCLUDES" + export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES" make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" V=1 done @@ -151,15 +156,15 @@ script: | for i in ${HOSTS}; do export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} mkdir build && cd build - EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i" - if [ -d "$EXTRA_INCLUDES" ]; then - export C_INCLUDE_PATH="$EXTRA_INCLUDES" - export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES" + ARCH_INCLUDES="$EXTRA_INCLUDES_BASE/$i" + if [ -d "$ARCH_INCLUDES" ]; then + EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}:${ARCH_INCLUDES}" else - unset C_INCLUDE_PATH - unset CPLUS_INCLUDE_PATH + EXTRA_INCLUDES="${EXTRA_INCLUDES_BASE}" fi - cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON + export C_INCLUDE_PATH="$EXTRA_INCLUDES" + export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES" + cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON -DCMAKE_SKIP_RPATH=ON make ${MAKEOPTS} chmod 755 bin/* cp ../LICENSE bin diff --git a/ANONYMITY_NETWORKS.md b/docs/ANONYMITY_NETWORKS.md index 3337b5fc3..3337b5fc3 100644 --- a/ANONYMITY_NETWORKS.md +++ b/docs/ANONYMITY_NETWORKS.md diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 7b184c00a..7b184c00a 100644 --- a/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md diff --git a/LEVIN_PROTOCOL.md b/docs/LEVIN_PROTOCOL.md index 207509146..43500fd06 100644 --- a/LEVIN_PROTOCOL.md +++ b/docs/LEVIN_PROTOCOL.md @@ -10,7 +10,7 @@ extensibility. One of the goals of this document is to clearly indicate what is being sent "on the wire" to identify metadata that could de-anonymize users over I2P/Tor. These issues will be addressed as they are found. See `ANONMITY_NETWORKS.md` in -the top-level folder for any outstanding issues. +the `docs` folder for any outstanding issues. > This document does not currently list all data being sent by the monero > protocol, that portion is a work-in-progress. Please take the time to do it diff --git a/README.i18n.md b/docs/README.i18n.md index 5df277624..5df277624 100644 --- a/README.i18n.md +++ b/docs/README.i18n.md diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md new file mode 100644 index 000000000..632366985 --- /dev/null +++ b/docs/RELEASE_CHECKLIST.md @@ -0,0 +1,68 @@ +- [ ] Security audit +- [ ] Code audit +- [ ] Ledger integration + - [ ] Implemented in Monero codebase (if needed) + - [ ] Ledger app integration coded by Ledger + - [ ] Ledger Monero app update available +- [ ] Trezor integration + - [ ] Implemented in Monero codebase (if needed) + - [ ] Trezor app integration coded by Trezor + - [ ] Trezor firmware update available (if needed) +- [ ] Fork height set + - [ ] Monero-announce mailer notice + - [ ] Twitter announcement + - [ ] Reddit announcement + - [ ] Getmonero.org announcement +- [ ] Notify wallets + - [ ] MyMonero + - [ ] Coinomi + - [ ] Exa Wallet + - [ ] Wookey Wallet + - [ ] X Wallet + - [ ] Guarda + - [ ] ZelCore + - [ ] Cake Wallet + - [ ] Monerujo + - [ ] Edge Wallet + - [ ] Exodus + - [ ] XMRWallet +- [ ] Notify exchanges + - [ ] https://web.getmonero.org/community/merchants/#exchanges +- [ ] Notify 3rd party payment processors + - [ ] https://web.getmonero.org/community/merchants/#payment-gateways +- [ ] Notify mining pools + - [ ] https://miningpoolstats.stream/monero +- [ ] Release tagged + - [ ] Update src/version.cpp.in with new version AND new name (if necessary) + - [ ] Update Gitian YML files in contrib/gitian/ to the new version number + - [ ] Update README.md with new fork table entry (or at least update the Recommended Monero version) + - [ ] Update contrib/gitian/README.md so that the instructions reflect the current version + - [ ] Update src/checkpoints/checkpoints.cpp with a recent hardcoded checkpoint + - [ ] Update src/blocks/checkpoints.dat with ./monero-blockchain-export --output-file checkpoints.dat --block-stop <recent block height> --blocksdat + - [ ] Update expected_block_hashes_hash in src/cryptonote_core/blockchain.cpp with checkpoints.dat sha256 hash +- [ ] Testnet forked +- [ ] Testnet testing/verification + - [ ] Ledger + - [ ] Trezor + - [ ] Release-specific testing + - [ ] RPC testing/update RPC documentation +- [ ] CLI reproducible builds validated +- [ ] CLI released + - [ ] https://web.getmonero.org/downloads/ updated + - [ ] Update hashes.txt on website + - [ ] Update downloads.yml on website + - [ ] Update auto-update DNS records + - [ ] Update redirects on downloads box + - [ ] Update seed nodes +- [ ] GUI released + - [ ] https://web.getmonero.org/downloads/ updated + - [ ] Update hashes.txt on website + - [ ] Update hashes.txt.sig on website + - [ ] Update downloads.yml on website + - [ ] Update auto-update DNS records + - [ ] Update redirects on downloads box +- [ ] Release Announcements + - [ ] Monero-announce mailer notice + - [ ] Twitter announcement + - [ ] Reddit announcement + - [ ] Getmonero.org announcement diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07d4d58c3..9904c5de7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,6 +75,8 @@ function (monero_add_executable name) PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") enable_stack_trace("${name}") + + monero_set_target_no_relink("${name}") endfunction () function (monero_add_library name) @@ -92,6 +94,7 @@ function (monero_add_library_with_deps) set(objlib obj_${MONERO_ADD_LIBRARY_NAME}) add_library(${objlib} OBJECT ${MONERO_ADD_LIBRARY_SOURCES}) add_library("${MONERO_ADD_LIBRARY_NAME}" $<TARGET_OBJECTS:${objlib}>) + monero_set_target_no_relink("${MONERO_ADD_LIBRARY_NAME}") if (MONERO_ADD_LIBRARY_DEPENDS) add_dependencies(${objlib} ${MONERO_ADD_LIBRARY_DEPENDS}) endif() diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt index 051c60886..445596a66 100644 --- a/src/blocks/CMakeLists.txt +++ b/src/blocks/CMakeLists.txt @@ -45,4 +45,4 @@ foreach(BLOB_NAME checkpoints testnet_blocks stagenet_blocks) ) endforeach() -add_library(blocks STATIC blocks.cpp ${GENERATED_SOURCES}) +monero_add_library(blocks blocks.cpp ${GENERATED_SOURCES}) diff --git a/src/common/powerof.h b/src/common/powerof.h new file mode 100644 index 000000000..0f6c6254a --- /dev/null +++ b/src/common/powerof.h @@ -0,0 +1,26 @@ +#pragma once + +#include <stdint.h> + +namespace tools +{ + template<uint64_t a, uint64_t b> + struct PowerOf + { + enum Data : uint64_t + { + // a^b = a * a^(b-1) + Value = a * PowerOf<a, b - 1>::Value, + }; + }; + + template<uint64_t a> + struct PowerOf<a, 0> + { + enum Data : uint64_t + { + // a^0 = 1 + Value = 1, + }; + }; +} diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index a4db99f83..bc17b7e81 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -128,7 +128,7 @@ #define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000 #define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000 -#define P2P_DEFAULT_CONNECTIONS_COUNT 8 +#define P2P_DEFAULT_CONNECTIONS_COUNT 12 #define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes #define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size #define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 93e3ef3bc..ad27f1358 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3068,9 +3068,21 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context if (tx.version >= 2) { if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2) { - MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1)); - tvc.m_invalid_output = true; - return false; + // two MLSAG txes went in due to a bug with txes that went into the txpool before the fork, grandfather them in + static const char * grandfathered[2] = { "c5151944f0583097ba0c88cd0f43e7fabb3881278aa2f73b3b0a007c5d34e910", "6f2f117cde6fbcf8d4a6ef8974fcac744726574ac38cf25d3322c996b21edd4c" }; + crypto::hash h0, h1; + epee::string_tools::hex_to_pod(grandfathered[0], h0); + epee::string_tools::hex_to_pod(grandfathered[1], h1); + if (cryptonote::get_transaction_hash(tx) == h0 || cryptonote::get_transaction_hash(tx) == h1) + { + MDEBUG("Grandfathering cryptonote::get_transaction_hash(tx) in"); + } + else + { + MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1)); + tvc.m_invalid_output = true; + return false; + } } } } @@ -3128,14 +3140,6 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr } } } - else if (rv.type == rct::RCTTypeCLSAG) - { - CHECK_AND_ASSERT_MES(rv.p.CLSAGs.size() == tx.vin.size(), false, "Bad CLSAGs size"); - for (size_t n = 0; n < tx.vin.size(); ++n) - { - rv.p.CLSAGs[n].I = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); - } - } else { CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type)); @@ -3617,19 +3621,6 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const } //------------------------------------------------------------------ -uint64_t Blockchain::get_fee_quantization_mask() -{ - static uint64_t mask = 0; - if (mask == 0) - { - mask = 1; - for (size_t n = PER_KB_FEE_QUANTIZATION_DECIMALS; n < CRYPTONOTE_DISPLAY_DECIMAL_POINT; ++n) - mask *= 10; - } - return mask; -} - -//------------------------------------------------------------------ uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version) { const uint64_t min_block_weight = get_min_block_weight(version); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index a9b7ca1da..a8e251c71 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -51,6 +51,7 @@ #include "string_tools.h" #include "rolling_median.h" #include "cryptonote_basic/cryptonote_basic.h" +#include "common/powerof.h" #include "common/util.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "rpc/core_rpc_server_commands_defs.h" @@ -591,7 +592,10 @@ namespace cryptonote * * @return the fee quantized mask */ - static uint64_t get_fee_quantization_mask(); + static uint64_t get_fee_quantization_mask() + { + return tools::PowerOf<10, CRYPTONOTE_DISPLAY_DECIMAL_POINT - PER_KB_FEE_QUANTIZATION_DECIMALS>::Value; + } /** * @brief get dynamic per kB or byte fee for a given block weight diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index fef411a0c..42b1c6c84 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1510,6 +1510,11 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- + bool core::is_synchronized() const + { + return m_pprotocol != nullptr && m_pprotocol->is_synchronized(); + } + //----------------------------------------------------------------------------------------------- void core::on_synchronized() { m_miner.on_synchronized(); @@ -1725,7 +1730,7 @@ namespace cryptonote m_starter_message_showed = true; } - m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this)); + relay_txpool_transactions(); // txpool handles periodic DB checking m_check_updates_interval.do_call(boost::bind(&core::check_updates, this)); m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this)); m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this)); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index c9d26e0ed..37981478c 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -224,14 +224,14 @@ namespace cryptonote * * @return true if the block was added to the main chain, otherwise false */ - virtual bool handle_block_found(block& b, block_verification_context &bvc); + virtual bool handle_block_found(block& b, block_verification_context &bvc) override; /** * @copydoc Blockchain::create_block_template * * @note see Blockchain::create_block_template */ - virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash); + virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) override; virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash); /** @@ -329,7 +329,7 @@ namespace cryptonote * * @note see Blockchain::get_current_blockchain_height() */ - uint64_t get_current_blockchain_height() const; + virtual uint64_t get_current_blockchain_height() const final; /** * @brief get the hash and height of the most recent block @@ -638,6 +638,13 @@ namespace cryptonote std::string print_pool(bool short_format) const; /** + * @brief gets the core synchronization status + * + * @return core synchronization status + */ + virtual bool is_synchronized() const final; + + /** * @copydoc miner::on_synchronized * * @note see miner::on_synchronized @@ -1065,7 +1072,6 @@ namespace cryptonote epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval; //!< interval for manual storing of Blockchain, if enabled epee::math_helper::once_a_time_seconds<60*60*2, true> m_fork_moaner; //!< interval for checking HardFork status - epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate diff --git a/src/cryptonote_core/i_core_events.h b/src/cryptonote_core/i_core_events.h index 03394d785..5d00858b5 100644 --- a/src/cryptonote_core/i_core_events.h +++ b/src/cryptonote_core/i_core_events.h @@ -39,6 +39,8 @@ namespace cryptonote virtual ~i_core_events() noexcept {} + virtual uint64_t get_current_blockchain_height() const = 0; + virtual bool is_synchronized() const = 0; virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0; }; } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 85bcf2246..0db133b62 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -91,6 +91,9 @@ namespace cryptonote time_t const MAX_RELAY_TIME = (60 * 60 * 4); // at most that many seconds between resends float const ACCEPT_THRESHOLD = 1.0f; + //! Max DB check interval for relayable txes + constexpr const std::chrono::minutes max_relayable_check{2}; + constexpr const std::chrono::seconds forward_delay_average{CRYPTONOTE_FORWARD_DELAY_AVERAGE}; // a kind of increasing backoff within min/max bounds @@ -115,12 +118,21 @@ namespace cryptonote else return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } + + // external lock must be held for the comparison+set to work properly + void set_if_less(std::atomic<time_t>& next_check, const time_t candidate) noexcept + { + if (candidate < next_check.load(std::memory_order_relaxed)) + next_check = candidate; + } } //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- - tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false) + tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_cookie(0), m_txpool_max_weight(DEFAULT_TXPOOL_MAX_WEIGHT), m_txpool_weight(0), m_mine_stem_txes(false), m_next_check(std::time(nullptr)) { - + // class code expects unsigned values throughout + if (m_next_check < time_t(0)) + throw std::runtime_error{"Unexpected time_t (system clock) value"}; } //--------------------------------------------------------------------------------- bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version) @@ -314,7 +326,10 @@ namespace cryptonote using clock = std::chrono::system_clock; auto last_relayed_time = std::numeric_limits<decltype(meta.last_relayed_time)>::max(); if (tx_relay == relay_method::forward) + { last_relayed_time = clock::to_time_t(clock::now() + crypto::random_poisson_seconds{forward_delay_average}()); + set_if_less(m_next_check, time_t(last_relayed_time)); + } // else the `set_relayed` function will adjust the time accordingly later //update transactions container @@ -728,16 +743,22 @@ namespace cryptonote } //--------------------------------------------------------------------------------- //TODO: investigate whether boolean return is appropriate - bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) const + bool tx_memory_pool::get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>> &txs) { - std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps; + using clock = std::chrono::system_clock; + const uint64_t now = time(NULL); + if (uint64_t{std::numeric_limits<time_t>::max()} < now || time_t(now) < m_next_check) + return false; + + uint64_t next_check = clock::to_time_t(clock::from_time_t(time_t(now)) + max_relayable_check); + std::vector<std::pair<crypto::hash, txpool_tx_meta_t>> change_timestamps; CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); LockedTXN lock(m_blockchain.get_db()); txs.reserve(m_blockchain.get_txpool_tx_count()); - m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){ + m_blockchain.for_all_txpool_txes([this, now, &txs, &change_timestamps, &next_check](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref *){ // 0 fee transactions are never relayed if(!meta.pruned && meta.fee > 0 && !meta.do_not_relay) { @@ -747,7 +768,10 @@ namespace cryptonote case relay_method::stem: case relay_method::forward: if (meta.last_relayed_time > now) + { + next_check = std::min(next_check, meta.last_relayed_time); return true; // continue to next tx + } change_timestamps.emplace_back(txid, meta); break; default: @@ -792,6 +816,8 @@ namespace cryptonote elem.second.last_relayed_time = now + get_relay_delay(now, elem.second.receive_time); m_blockchain.update_txpool_tx(elem.first, elem.second); } + + m_next_check = time_t(next_check); return true; } //--------------------------------------------------------------------------------- @@ -799,6 +825,7 @@ namespace cryptonote { crypto::random_poisson_seconds embargo_duration{dandelionpp_embargo_average}; const auto now = std::chrono::system_clock::now(); + uint64_t next_relay = uint64_t{std::numeric_limits<time_t>::max()}; CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); @@ -815,7 +842,10 @@ namespace cryptonote meta.relayed = true; if (meta.dandelionpp_stem) + { meta.last_relayed_time = std::chrono::system_clock::to_time_t(now + embargo_duration()); + next_relay = std::min(next_relay, meta.last_relayed_time); + } else meta.last_relayed_time = std::chrono::system_clock::to_time_t(now); @@ -829,6 +859,7 @@ namespace cryptonote } } lock.commit(); + set_if_less(m_next_check, time_t(next_relay)); } //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_transactions_count(bool include_sensitive) const @@ -1391,7 +1422,10 @@ namespace cryptonote txpool_tx_meta_t meta; if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta)) { - MERROR(" failed to find tx meta"); + static bool warned = false; + if (!warned) + MERROR(" failed to find tx meta: " << sorted_it->second << " (will only print once)"); + warned = true; continue; } LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method()); diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 8955d7551..ab2a57ea2 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -31,6 +31,7 @@ #pragma once #include "include_base_utils.h" +#include <atomic> #include <set> #include <tuple> #include <unordered_map> @@ -329,11 +330,14 @@ namespace cryptonote * isn't old enough that relaying it is considered harmful * Note a transaction can be "relayable" even if do_not_relay is true * + * This function will skip all DB checks if an insufficient amount of + * time since the last call. + * * @param txs return-by-reference the transactions and their hashes * - * @return true + * @return True if DB was checked, false if DB checks skipped. */ - bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs) const; + bool get_relayable_transactions(std::vector<std::tuple<crypto::hash, cryptonote::blobdata, relay_method>>& txs); /** * @brief tell the pool that certain transactions were just relayed @@ -609,6 +613,9 @@ private: mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache; std::unordered_map<crypto::hash, transaction> m_parsed_tx_cache; + + //! Next timestamp that a DB check for relayable txes is allowed + std::atomic<time_t> m_next_check; }; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 89860fe41..61aac6d81 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -104,7 +104,7 @@ namespace cryptonote bool get_payload_sync_data(CORE_SYNC_DATA& hshd); bool on_callback(cryptonote_connection_context& context); t_core& get_core(){return m_core;} - bool is_synchronized(){return m_synchronized;} + virtual bool is_synchronized() const final { return !no_sync() && m_synchronized; } void log_connections(); std::list<connection_info> get_connections(); const block_queue &get_block_queue() const { return m_block_queue; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 337885509..a72b7db79 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -430,7 +430,7 @@ namespace cryptonote MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; - if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks + if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks { LOG_DEBUG_CC(context, "Received new block while syncing, ignored"); return 1; @@ -501,7 +501,7 @@ namespace cryptonote MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; - if(!is_synchronized() || m_no_sync) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks + if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks { LOG_DEBUG_CC(context, "Received new block while syncing, ignored"); return 1; @@ -929,7 +929,7 @@ namespace cryptonote // while syncing, core will lock for a long time, so we ignore // those txes as they aren't really needed anyway, and avoid a // long block before replying - if(!is_synchronized() || m_no_sync) + if(!is_synchronized()) { LOG_DEBUG_CC(context, "Received new tx while syncing, ignored"); return 1; @@ -1091,6 +1091,13 @@ namespace cryptonote //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size()); + if(arg.blocks.empty()) + { + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks"); + drop_connection(context, true, false); + ++m_sync_bad_spans_downloaded; + return 1; + } if(context.m_last_response_height > arg.current_blockchain_height) { LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height @@ -2538,7 +2545,7 @@ skip: local mempool before doing the relay. The code was already updating the DB twice on received transactions - it is difficult to workaround this due to the internal design. */ - return m_p2p->send_txs(std::move(arg.txs), zone, source, m_core, tx_relay) != epee::net_utils::zone::invalid; + return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid; } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h index 1c7635fd8..79c2edf1d 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h @@ -40,6 +40,7 @@ namespace cryptonote /************************************************************************/ struct i_cryptonote_protocol { + virtual bool is_synchronized() const = 0; virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0; virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, const boost::uuids::uuid& source, epee::net_utils::zone zone, relay_method tx_relay)=0; //virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0; @@ -50,6 +51,10 @@ namespace cryptonote /************************************************************************/ struct cryptonote_protocol_stub: public i_cryptonote_protocol { + virtual bool is_synchronized() const final + { + return false; + } virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context) { return false; diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 7c482156f..75ba68d3b 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -105,8 +105,44 @@ namespace levin return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())}; } - //! \return All outgoing connections supporting fragments in `connections`. - std::vector<boost::uuids::uuid> get_out_connections(connections& p2p) + uint64_t get_median_remote_height(connections& p2p) + { + std::vector<uint64_t> remote_heights; + remote_heights.reserve(connection_id_reserve_size); + p2p.foreach_connection([&remote_heights] (detail::p2p_context& context) { + if (!context.m_is_income) + { + remote_heights.emplace_back(context.m_remote_blockchain_height); + } + return true; + }); + + if (remote_heights.empty()) + { + return 0; + } + + const size_t n = remote_heights.size() / 2; + std::sort(remote_heights.begin(), remote_heights.end()); + if (remote_heights.size() % 2 != 0) + { + return remote_heights[n]; + } + return remote_heights[n-1]; + } + + uint64_t get_blockchain_height(connections& p2p, const i_core_events* core) + { + const uint64_t local_blockchain_height = core->get_current_blockchain_height(); + if (core->is_synchronized()) + { + return local_blockchain_height; + } + return std::max(local_blockchain_height, get_median_remote_height(p2p)); + } + + //! \return Outgoing connections supporting fragments in `connections` filtered by blockchain height. + std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t blockchain_height) { std::vector<boost::uuids::uuid> outs; outs.reserve(connection_id_reserve_size); @@ -115,15 +151,21 @@ namespace levin the reserve call so a strand is not used. Investigate if there is lots of waiting in here. */ - p2p.foreach_connection([&outs] (detail::p2p_context& context) { - if (!context.m_is_income) + p2p.foreach_connection([&outs, blockchain_height] (detail::p2p_context& context) { + if (!context.m_is_income && context.m_remote_blockchain_height >= blockchain_height) outs.emplace_back(context.m_connection_id); return true; }); + MDEBUG("Found " << outs.size() << " out connections having height >= " << blockchain_height); return outs; } + std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, const i_core_events* core) + { + return get_out_connections(p2p, get_blockchain_height(p2p, core)); + } + std::string make_tx_payload(std::vector<blobdata>&& txs, const bool pad, const bool fluff) { NOTIFY_NEW_TRANSACTIONS::request request{}; @@ -233,7 +275,7 @@ namespace levin { struct zone { - explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, bool is_public, bool pad_txs) + explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs) : p2p(std::move(p2p)), noise(std::move(noise_in)), next_epoch(io_service), @@ -243,7 +285,7 @@ namespace levin channels(), flush_time(std::chrono::steady_clock::time_point::max()), connection_count(0), - is_public(is_public), + nzone(zone), pad_txs(pad_txs), fluffing(false) { @@ -260,7 +302,7 @@ namespace levin std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand` std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time - const bool is_public; //!< Zone is public ipv4/ipv6 connections + const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor const bool pad_txs; //!< Pad txs to the next boundary for privacy bool fluffing; //!< Zone is in Dandelion++ fluff epoch }; @@ -297,7 +339,8 @@ namespace levin if (!channel.connection.is_nil()) channel.queue.push_back(std::move(message_)); else if (destination_ == 0 && zone_->connection_count == 0) - MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections"); + MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) << + " - no available outbound connections"); } }; @@ -410,7 +453,7 @@ namespace levin zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context) { // When i2p/tor, only fluff to outbound connections - if (source != context.m_connection_id && (zone->is_public || !context.m_is_income)) + if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income)) { available = true; if (context.fluff_txs.empty()) @@ -524,12 +567,7 @@ namespace levin if (!zone_ || !core_ || txs_.empty()) return; - if (zone_->fluffing) - { - core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff); - fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_); - } - else // forward tx in stem + if (!zone_->fluffing) { core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem); for (int tries = 2; 0 < tries; tries--) @@ -544,11 +582,14 @@ namespace levin } // connection list may be outdated, try again - update_channels::run(zone_, get_out_connections(*zone_->p2p)); + update_channels::run(zone_, get_out_connections(*zone_->p2p, core_)); } MERROR("Unable to send transaction(s) via Dandelion++ stem"); } + + core_->on_transactions_relayed(epee::to_span(txs_), relay_method::fluff); + fluff_notify::run(std::move(zone_), epee::to_span(txs_), source_); } }; @@ -577,7 +618,7 @@ namespace levin assert(zone_->strand.running_in_this_thread()); - if (zone_->is_public) + if (zone_->nzone == epee::net_utils::zone::public_) MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem")); zone_->map = std::move(map_); @@ -591,8 +632,9 @@ namespace levin { std::shared_ptr<detail::zone> zone_; const std::size_t channel_; + const i_core_events* core_; - static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index) + static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index, const i_core_events* core) { if (!zone) return; @@ -600,7 +642,7 @@ namespace levin noise_channel& channel = zone->channels.at(index); channel.next_noise.expires_at(start + noise_min_delay + random_duration(noise_delay_range)); channel.next_noise.async_wait( - channel.strand.wrap(send_noise{std::move(zone), index}) + channel.strand.wrap(send_noise{std::move(zone), index, core}) ); } @@ -644,16 +686,18 @@ namespace levin { channel.active = nullptr; channel.connection = boost::uuids::nil_uuid(); + auto height = get_blockchain_height(*zone_->p2p, core_); - auto connections = get_out_connections(*zone_->p2p); + auto connections = get_out_connections(*zone_->p2p, height); if (connections.empty()) - MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)"); + MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) << + " - no suitable outbound connections at height " << height); zone_->strand.post(update_channels{zone_, std::move(connections)}); } } - wait(start, std::move(zone_), channel_); + wait(start, std::move(zone_), channel_, core_); } }; @@ -665,6 +709,7 @@ namespace levin std::chrono::seconds min_epoch_; std::chrono::seconds epoch_range_; std::size_t count_; + const i_core_events* core_; //! \pre Should not be invoked within any strand to prevent blocking. void operator()(const boost::system::error_code error = {}) @@ -677,8 +722,9 @@ namespace levin const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY; const auto start = std::chrono::steady_clock::now(); + auto connections = get_out_connections(*(zone_->p2p), core_); zone_->strand.dispatch( - change_channels{zone_, net::dandelionpp::connection_map{get_out_connections(*(zone_->p2p)), count_}, fluffing} + change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing} ); detail::zone& alias = *zone_; @@ -688,24 +734,25 @@ namespace levin }; } // anonymous - notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, const bool is_public, const bool pad_txs) - : zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), is_public, pad_txs)) + notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core) + : zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs)) + , core_(std::addressof(core)) { if (!zone_->p2p) throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"}; const bool noise_enabled = !zone_->noise.empty(); - if (noise_enabled || is_public) + if (noise_enabled || zone == epee::net_utils::zone::public_) { const auto now = std::chrono::steady_clock::now(); const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch; const auto epoch_range = noise_enabled ? noise_epoch_range : dandelionpp_epoch_range; const std::size_t out_count = noise_enabled ? CRYPTONOTE_NOISE_CHANNELS : CRYPTONOTE_DANDELIONPP_STEMS; - start_epoch{zone_, min_epoch, epoch_range, out_count}(); + start_epoch{zone_, min_epoch, epoch_range, out_count, core_}(); for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel) - send_noise::wait(now, zone_, channel); + send_noise::wait(now, zone_, channel, core_); } } @@ -726,7 +773,7 @@ namespace levin return; zone_->strand.dispatch( - update_channels{zone_, get_out_connections(*(zone_->p2p))} + update_channels{zone_, get_out_connections(*(zone_->p2p), core_)} ); } @@ -753,7 +800,7 @@ namespace levin zone_->flush_txs.cancel(); } - bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay) + bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay) { if (txs.empty()) return true; @@ -785,7 +832,7 @@ namespace levin tx_relay = relay_method::local; // do not put into stempool embargo (hopefully not there already!). } - core.on_transactions_relayed(epee::to_span(txs), tx_relay); + core_->on_transactions_relayed(epee::to_span(txs), tx_relay); // Padding is not useful when using noise mode. Send as stem so receiver // forwards in Dandelion++ mode. @@ -817,11 +864,11 @@ namespace levin case relay_method::stem: case relay_method::forward: case relay_method::local: - if (zone_->is_public) + if (zone_->nzone == epee::net_utils::zone::public_) { // this will change a local/forward tx to stem or fluff ... zone_->strand.dispatch( - dandelionpp_notify{zone_, std::addressof(core), std::move(txs), source} + dandelionpp_notify{zone_, core_, std::move(txs), source} ); break; } @@ -832,7 +879,7 @@ namespace levin routine. A "fluff" over i2p/tor is not the same as a "fluff" over ipv4/6. Marking it as "fluff" here will make the tx immediately visible externally from this node, which is not desired. */ - core.on_transactions_relayed(epee::to_span(txs), tx_relay); + core_->on_transactions_relayed(epee::to_span(txs), tx_relay); zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source}); break; } diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h index 957794b12..abbf9d461 100644 --- a/src/cryptonote_protocol/levin_notify.h +++ b/src/cryptonote_protocol/levin_notify.h @@ -69,6 +69,7 @@ namespace levin class notify { std::shared_ptr<detail::zone> zone_; + i_core_events* core_; public: struct status @@ -80,10 +81,11 @@ namespace levin //! Construct an instance that cannot notify. notify() noexcept : zone_(nullptr) + , core_(nullptr) {} //! Construct an instance with available notification `zones`. - explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, bool is_public, bool pad_txs); + explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core); notify(const notify&) = delete; notify(notify&&) = default; @@ -123,7 +125,7 @@ namespace levin particular stem. \return True iff the notification is queued for sending. */ - bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay); + bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay); }; } // levin } // net diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 504b104b0..aac891c4a 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -50,7 +50,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& { if (args.size() > 3) { - std::cout << "use: print_pl [white] [gray] [<limit>] [pruned] [publicrpc]" << std::endl; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; return true; } @@ -79,7 +79,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& } else if (!epee::string_tools::get_xtype_from_string(limit, args[i])) { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } @@ -90,56 +90,79 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& bool t_command_parser_executor::print_peer_list_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_peer_list_stats(); } bool t_command_parser_executor::save_blockchain(const std::vector<std::string>& args) { - if (!args.empty()) return false; - + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.save_blockchain(); } bool t_command_parser_executor::show_hash_rate(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_hash_rate(); } bool t_command_parser_executor::hide_hash_rate(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.hide_hash_rate(); } bool t_command_parser_executor::show_difficulty(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_difficulty(); } bool t_command_parser_executor::show_status(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_status(); } bool t_command_parser_executor::print_connections(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_connections(); } bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_net_stats(); } @@ -148,8 +171,8 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str { if(!args.size()) { - std::cout << "need block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } uint64_t start_index = 0; uint64_t end_index = 0; @@ -158,20 +181,20 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str int64_t nblocks; if(!epee::string_tools::get_xtype_from_string(nblocks, args[0])) { - std::cout << "wrong number of blocks" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_info(nblocks, (uint64_t)-nblocks); } if(!epee::string_tools::get_xtype_from_string(start_index, args[0])) { - std::cout << "wrong starter block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong starter block index parameter. For more details, use the help command." << std::endl; + return true; } if(args.size() >1 && !epee::string_tools::get_xtype_from_string(end_index, args[1])) { - std::cout << "wrong end block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong end block index parameter. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_info(start_index, end_index); @@ -181,7 +204,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar { if(args.size() > 1) { - std::cout << "use: set_log [<log_level_number_0-4> | <categories>]" << std::endl; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; return true; } @@ -195,7 +218,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar { if(4 < l) { - std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << std::endl; + std::cout << "Invalid syntax: Wrong number range, use: set_log <log_level_number_0-4>. For more details, use the help command." << std::endl; return true; } return m_executor.set_log_level(l); @@ -208,7 +231,10 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar bool t_command_parser_executor::print_height(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_height(); } @@ -223,14 +249,14 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args include_hex = true; else { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } if (args.empty()) { - std::cout << "expected: print_block (<block_hash> | <block_height>) [+hex]" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } const std::string& arg = args.front(); @@ -248,7 +274,7 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args } } - return false; + return true; } bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args) @@ -267,13 +293,13 @@ bool t_command_parser_executor::print_transaction(const std::vector<std::string> include_json = true; else { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } if (args.empty()) { - std::cout << "expected: print_tx <transaction_hash> [+meta] [+hex] [+json]" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -291,7 +317,7 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string { if (args.empty()) { - std::cout << "expected: is_key_image_spent <key_image>" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -309,21 +335,30 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string bool t_command_parser_executor::print_transaction_pool_long(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_long(); } bool t_command_parser_executor::print_transaction_pool_short(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_short(); } bool t_command_parser_executor::print_transaction_pool_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_stats(); } @@ -332,7 +367,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg { if(!args.size()) { - std::cout << "Please specify a wallet address to mine for: start_mining <addr> [<threads>|auto]" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -353,7 +388,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg { if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, address_str)) { - std::cout << "target account address has wrong format" << std::endl; + std::cout << "Invalid syntax: Target account address has wrong format. For more details, use the help command." << std::endl; return true; } else @@ -389,9 +424,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg bool ignore_battery = false; if(args.size() > 4) { - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } - + if(args.size() == 4) { if(args[3] == "true" || command_line::is_yes(args[3]) || args[3] == "1") @@ -400,10 +436,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg } else if(args[3] != "false" && !command_line::is_no(args[3]) && args[3] != "0") { - return false; + std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl; + return true; } - } - + } + if(args.size() >= 3) { if(args[2] == "true" || command_line::is_yes(args[2]) || args[2] == "1") @@ -412,10 +449,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg } else if(args[2] != "false" && !command_line::is_no(args[2]) && args[2] != "0") { - return false; + std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl; + return true; } } - + if(args.size() >= 2) { if (args[1] == "auto" || args[1] == "autodetect") @@ -436,7 +474,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg bool t_command_parser_executor::stop_mining(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.stop_mining(); } @@ -448,21 +489,31 @@ bool t_command_parser_executor::mining_status(const std::vector<std::string>& ar bool t_command_parser_executor::stop_daemon(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.stop_daemon(); } bool t_command_parser_executor::print_status(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_status(); } bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit(); } @@ -471,8 +522,8 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(limit, limit); @@ -480,7 +531,11 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit_up(); } @@ -489,8 +544,8 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(0, limit); @@ -498,7 +553,11 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit_down(); } @@ -507,8 +566,8 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(limit, 0); @@ -525,12 +584,13 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args) set = true; } } - + catch(const std::exception& ex) { _erro("stoi exception"); - return false; + std::cout << "Invalid syntax: Failed to parse number. For more details, use the help command." << std::endl; + return true; } - + return m_executor.out_peers(set, limit); } @@ -548,7 +608,8 @@ bool t_command_parser_executor::in_peers(const std::vector<std::string>& args) catch(const std::exception& ex) { _erro("stoi exception"); - return false; + std::cout << "Invalid syntax: Failed to parse number." << std::endl; + return true; } return m_executor.in_peers(set, limit); @@ -565,26 +626,37 @@ bool t_command_parser_executor::hard_fork_info(const std::vector<std::string>& a version = std::stoi(args[0]); } catch(const std::exception& ex) { - return false; + std::cout << "Invalid syntax: Failed to parse version number. For more details, use the help command." << std::endl; + return true; + } + if (version <= 0 || version > 255) { + std::cout << "Invalid syntax: Unknown version number. Must be between 0 and 255. For more details, use the help command." << std::endl; + return true; } - if (version <= 0 || version > 255) - return false; } else { - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } return m_executor.hard_fork_info(version); } bool t_command_parser_executor::show_bans(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } + return m_executor.print_bans(); } bool t_command_parser_executor::ban(const std::vector<std::string>& args) { - if (args.size() != 1 && args.size() != 2) return false; + if (args.size() != 1 && args.size() != 2) { + std::cout << "Invalid syntax: Expects one or two parameters. For more details, use the help command." << std::endl; + return true; + } std::string ip = args[0]; time_t seconds = P2P_IP_BLOCKTIME; if (args.size() > 1) @@ -595,11 +667,13 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args) } catch (const std::exception &e) { - return false; + std::cout << "Invalid syntax: Failed to parse seconds. For more details, use the help command." << std::endl; + return true; } if (seconds == 0) { - return false; + std::cout << "Seconds must be greater than 0." << std::endl; + return true; } } return m_executor.ban(ip, seconds); @@ -607,21 +681,31 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args) bool t_command_parser_executor::unban(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } + std::string ip = args[0]; return m_executor.unban(ip); } bool t_command_parser_executor::banned(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } std::string address = args[0]; return m_executor.banned(address); } bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& args) { - if (args.size() > 1) return false; + if (args.size() > 1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } std::string txid; if (args.size() == 1) @@ -629,7 +713,7 @@ bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& arg crypto::hash hash; if (!parse_hash256(args[0], hash)) { - std::cout << "failed to parse tx id" << std::endl; + std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl; return true; } txid = args[0]; @@ -662,7 +746,7 @@ bool t_command_parser_executor::output_histogram(const std::vector<std::string>& } else { - std::cout << "Invalid syntax: more than two non-amount parameters" << std::endl; + std::cout << "Invalid syntax: More than two non-amount parameters. For more details, use the help command." << std::endl; return true; } } @@ -673,20 +757,21 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::str { if(!args.size()) { - std::cout << "need block height parameter" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } + uint64_t height = 0; uint64_t count = 0; if(!epee::string_tools::get_xtype_from_string(height, args[0])) { - std::cout << "wrong starter block height parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong starter block height parameter. For more details, use the help command." << std::endl; + return true; } if(args.size() >1 && !epee::string_tools::get_xtype_from_string(count, args[1])) { std::cout << "wrong count parameter" << std::endl; - return false; + return true; } return m_executor.print_coinbase_tx_sum(height, count); @@ -696,8 +781,8 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a { if(args.size() > 1) { - std::cout << "usage: alt_chain_info [block_hash|>N|-N]" << std::endl; - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } std::string tip; @@ -709,16 +794,16 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a { if (!epee::string_tools::get_xtype_from_string(above, args[0].c_str() + 1)) { - std::cout << "invalid above parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Invalid above parameter. For more details, use the help command." << std::endl; + return true; } } else if (args[0].size() > 0 && args[0][0] == '-') { if (!epee::string_tools::get_xtype_from_string(last_blocks, args[0].c_str() + 1)) { - std::cout << "invalid last_blocks parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Invalid last_blocks parameter. For more details, use the help command." << std::endl; + return true; } } else @@ -734,15 +819,15 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector { if(args.size() != 1) { - std::cout << "Exactly one parameter is needed" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } uint64_t nblocks = 0; if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0) { - std::cout << "wrong number of blocks" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_dynamic_stats(nblocks); @@ -750,10 +835,10 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector bool t_command_parser_executor::update(const std::vector<std::string>& args) { - if(args.size() != 1) + if (args.size() != 1) { - std::cout << "Exactly one parameter is needed: check, download, or update" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } return m_executor.update(args.front()); @@ -761,13 +846,17 @@ bool t_command_parser_executor::update(const std::vector<std::string>& args) bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) + { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } std::string txid; crypto::hash hash; if (!parse_hash256(args[0], hash)) { - std::cout << "failed to parse tx id" << std::endl; + std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl; return true; } txid = args[0]; @@ -776,7 +865,10 @@ bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args) bool t_command_parser_executor::sync_info(const std::vector<std::string>& args) { - if (args.size() != 0) return false; + if (args.size() != 0) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.sync_info(); } @@ -785,8 +877,8 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args) { if (args.size() != 1) { - std::cout << "Exactly one parameter is needed" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } try @@ -794,21 +886,24 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args) uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]); if (nblocks < 1) { - std::cout << "number of blocks must be greater than 0" << std::endl; - return false; + std::cout << "Invalid syntax: Number of blocks must be greater than 0. For more details, use the help command." << std::endl; + return true; } return m_executor.pop_blocks(nblocks); } catch (const boost::bad_lexical_cast&) { - std::cout << "number of blocks must be a number greater than 0" << std::endl; + std::cout << "Invalid syntax: Number of blocks must be a number greater than 0. For more details, use the help command." << std::endl; } - return false; + return true; } bool t_command_parser_executor::rpc_payments(const std::vector<std::string>& args) { - if (args.size() != 0) return false; + if (args.size() != 0) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.rpc_payments(); } @@ -820,7 +915,11 @@ bool t_command_parser_executor::version(const std::vector<std::string>& args) bool t_command_parser_executor::prune_blockchain(const std::vector<std::string>& args) { - if (args.size() > 1) return false; + if (args.size() > 1) + { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } if (args.empty() || args[0] != "confirm") { @@ -846,7 +945,8 @@ bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::stri const size_t args_count = args.size(); if (args_count < 1 || args_count > 3) { - return false; + std::cout << "Invalid syntax: Wrong number of parameters. For more details, use the help command." << std::endl; + return true; } return m_executor.set_bootstrap_daemon( diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index ac4c30726..dd5f76188 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -223,7 +223,8 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "hard_fork_info" , std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1) - , "Print the hard fork voting information." + , "hard_fork_info <version>" + , "Print the hard fork voting information. If given a version, prints whether is this version enabled." ); m_command_lookup.set_handler( "bans" @@ -314,6 +315,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "prune_blockchain" , std::bind(&t_command_parser_executor::prune_blockchain, &m_parser, p::_1) + , "prune_blockchain [confirm]" , "Prune the blockchain." ); m_command_lookup.set_handler( diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index f2ae6dcc3..3db8fbcb4 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -249,7 +249,7 @@ int main(int argc, char const * argv[]) command_line::get_arg(vm, cryptonote::arg_data_dir)); #ifdef WIN32 - if (isFat32(data_dir.root_name().c_str())) + if (isFat32(data_dir.root_path().c_str())) { MERROR("Data directory resides on FAT32 volume that has 4GiB file size limit, blockchain might get corrupted."); } diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 3e0afeb65..384b776ee 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -83,44 +83,33 @@ namespace hw { // Must be sorted in ascending order by the code #define LEDGER_STATUS(status) {status, #status} constexpr Status status_codes[] = { - LEDGER_STATUS(SW_BYTES_REMAINING_00), - LEDGER_STATUS(SW_WARNING_STATE_UNCHANGED), - LEDGER_STATUS(SW_STATE_TERMINATED), - LEDGER_STATUS(SW_MORE_DATA_AVAILABLE), + LEDGER_STATUS(SW_OK), LEDGER_STATUS(SW_WRONG_LENGTH), - LEDGER_STATUS(SW_LOGICAL_CHANNEL_NOT_SUPPORTED), - LEDGER_STATUS(SW_SECURE_MESSAGING_NOT_SUPPORTED), - LEDGER_STATUS(SW_LAST_COMMAND_EXPECTED), - LEDGER_STATUS(SW_COMMAND_CHAINING_NOT_SUPPORTED), + LEDGER_STATUS(SW_SECURITY_PIN_LOCKED), LEDGER_STATUS(SW_SECURITY_LOAD_KEY), LEDGER_STATUS(SW_SECURITY_COMMITMENT_CONTROL), LEDGER_STATUS(SW_SECURITY_AMOUNT_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_COMMITMENT_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_OUTKEYS_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_MAXOUTPUT_REACHED), - LEDGER_STATUS(SW_SECURITY_TRUSTED_INPUT), - LEDGER_STATUS(SW_CLIENT_NOT_SUPPORTED), - LEDGER_STATUS(SW_SECURITY_STATUS_NOT_SATISFIED), - LEDGER_STATUS(SW_FILE_INVALID), - LEDGER_STATUS(SW_PIN_BLOCKED), - LEDGER_STATUS(SW_DATA_INVALID), - LEDGER_STATUS(SW_CONDITIONS_NOT_SATISFIED), + LEDGER_STATUS(SW_SECURITY_HMAC), + LEDGER_STATUS(SW_SECURITY_RANGE_VALUE), + LEDGER_STATUS(SW_SECURITY_INTERNAL), + LEDGER_STATUS(SW_SECURITY_MAX_SIGNATURE_REACHED), + LEDGER_STATUS(SW_SECURITY_PREFIX_HASH), + LEDGER_STATUS(SW_SECURITY_LOCKED), LEDGER_STATUS(SW_COMMAND_NOT_ALLOWED), - LEDGER_STATUS(SW_APPLET_SELECT_FAILED), + LEDGER_STATUS(SW_SUBCOMMAND_NOT_ALLOWED), + LEDGER_STATUS(SW_DENY), + LEDGER_STATUS(SW_KEY_NOT_SET), LEDGER_STATUS(SW_WRONG_DATA), - LEDGER_STATUS(SW_FUNC_NOT_SUPPORTED), - LEDGER_STATUS(SW_FILE_NOT_FOUND), - LEDGER_STATUS(SW_RECORD_NOT_FOUND), - LEDGER_STATUS(SW_FILE_FULL), - LEDGER_STATUS(SW_INCORRECT_P1P2), - LEDGER_STATUS(SW_REFERENCED_DATA_NOT_FOUND), + LEDGER_STATUS(SW_WRONG_DATA_RANGE), + LEDGER_STATUS(SW_IO_FULL), + LEDGER_STATUS(SW_CLIENT_NOT_SUPPORTED), LEDGER_STATUS(SW_WRONG_P1P2), - LEDGER_STATUS(SW_CORRECT_LENGTH_00), LEDGER_STATUS(SW_INS_NOT_SUPPORTED), - LEDGER_STATUS(SW_CLA_NOT_SUPPORTED), - LEDGER_STATUS(SW_UNKNOWN), - LEDGER_STATUS(SW_OK), - LEDGER_STATUS(SW_ALGORITHM_UNSUPPORTED) + LEDGER_STATUS(SW_PROTOCOL_NOT_SUPPORTED), + LEDGER_STATUS(SW_UNKNOWN) }; const char *Status::to_string(unsigned int code) diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index 5cb834e02..00ff05ec5 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -59,44 +59,33 @@ namespace hw { #ifdef WITH_DEVICE_LEDGER // Origin: https://github.com/LedgerHQ/ledger-app-monero/blob/master/src/monero_types.h - #define SW_BYTES_REMAINING_00 0x6100 - #define SW_WARNING_STATE_UNCHANGED 0x6200 - #define SW_STATE_TERMINATED 0x6285 - #define SW_MORE_DATA_AVAILABLE 0x6310 - #define SW_WRONG_LENGTH 0x6700 - #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 - #define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 - #define SW_LAST_COMMAND_EXPECTED 0x6883 - #define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884 - #define SW_SECURITY_LOAD_KEY 0x6900 - #define SW_SECURITY_COMMITMENT_CONTROL 0x6911 - #define SW_SECURITY_AMOUNT_CHAIN_CONTROL 0x6912 - #define SW_SECURITY_COMMITMENT_CHAIN_CONTROL 0x6913 - #define SW_SECURITY_OUTKEYS_CHAIN_CONTROL 0x6914 - #define SW_SECURITY_MAXOUTPUT_REACHED 0x6915 - #define SW_SECURITY_TRUSTED_INPUT 0x6916 - #define SW_CLIENT_NOT_SUPPORTED 0x6930 - #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 - #define SW_FILE_INVALID 0x6983 - #define SW_PIN_BLOCKED 0x6983 - #define SW_DATA_INVALID 0x6984 - #define SW_CONDITIONS_NOT_SATISFIED 0x6985 - #define SW_COMMAND_NOT_ALLOWED 0x6986 - #define SW_APPLET_SELECT_FAILED 0x6999 - #define SW_WRONG_DATA 0x6a80 - #define SW_FUNC_NOT_SUPPORTED 0x6a81 - #define SW_FILE_NOT_FOUND 0x6a82 - #define SW_RECORD_NOT_FOUND 0x6a83 - #define SW_FILE_FULL 0x6a84 - #define SW_INCORRECT_P1P2 0x6a86 - #define SW_REFERENCED_DATA_NOT_FOUND 0x6a88 - #define SW_WRONG_P1P2 0x6b00 - #define SW_CORRECT_LENGTH_00 0x6c00 - #define SW_INS_NOT_SUPPORTED 0x6d00 - #define SW_CLA_NOT_SUPPORTED 0x6e00 - #define SW_UNKNOWN 0x6f00 - #define SW_OK 0x9000 - #define SW_ALGORITHM_UNSUPPORTED 0x9484 + #define SW_OK 0x9000 + #define SW_WRONG_LENGTH 0x6700 + #define SW_SECURITY_PIN_LOCKED 0x6910 + #define SW_SECURITY_LOAD_KEY 0x6911 + #define SW_SECURITY_COMMITMENT_CONTROL 0x6912 + #define SW_SECURITY_AMOUNT_CHAIN_CONTROL 0x6913 + #define SW_SECURITY_COMMITMENT_CHAIN_CONTROL 0x6914 + #define SW_SECURITY_OUTKEYS_CHAIN_CONTROL 0x6915 + #define SW_SECURITY_MAXOUTPUT_REACHED 0x6916 + #define SW_SECURITY_HMAC 0x6917 + #define SW_SECURITY_RANGE_VALUE 0x6918 + #define SW_SECURITY_INTERNAL 0x6919 + #define SW_SECURITY_MAX_SIGNATURE_REACHED 0x691A + #define SW_SECURITY_PREFIX_HASH 0x691B + #define SW_SECURITY_LOCKED 0x69EE + #define SW_COMMAND_NOT_ALLOWED 0x6980 + #define SW_SUBCOMMAND_NOT_ALLOWED 0x6981 + #define SW_DENY 0x6982 + #define SW_KEY_NOT_SET 0x6983 + #define SW_WRONG_DATA 0x6984 + #define SW_WRONG_DATA_RANGE 0x6985 + #define SW_IO_FULL 0x6986 + #define SW_CLIENT_NOT_SUPPORTED 0x6A30 + #define SW_WRONG_P1P2 0x6b00 + #define SW_INS_NOT_SUPPORTED 0x6d00 + #define SW_PROTOCOL_NOT_SUPPORTED 0x6e00 + #define SW_UNKNOWN 0x6f00 namespace { bool apdu_verbose =true; diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index 1c5dca0d7..aee1fa593 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -146,6 +146,7 @@ namespace nodetool const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: <network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""}; const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""}; + const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"}; const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false}; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index e81371783..87fec9994 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -164,6 +164,7 @@ namespace nodetool network_zone() : m_connect(nullptr), m_net_server(epee::net_utils::e_connection_type_P2P), + m_seed_nodes(), m_bind_ip(), m_bind_ipv6_address(), m_port(), @@ -175,7 +176,9 @@ namespace nodetool m_proxy_address(), m_current_number_of_out_peers(0), m_current_number_of_in_peers(0), - m_can_pingback(false) + m_seed_nodes_lock(), + m_can_pingback(false), + m_seed_nodes_initialized(false) { set_config_defaults(); } @@ -183,6 +186,7 @@ namespace nodetool network_zone(boost::asio::io_service& public_service) : m_connect(nullptr), m_net_server(public_service, epee::net_utils::e_connection_type_P2P), + m_seed_nodes(), m_bind_ip(), m_bind_ipv6_address(), m_port(), @@ -194,13 +198,16 @@ namespace nodetool m_proxy_address(), m_current_number_of_out_peers(0), m_current_number_of_in_peers(0), - m_can_pingback(false) + m_seed_nodes_lock(), + m_can_pingback(false), + m_seed_nodes_initialized(false) { set_config_defaults(); } connect_func* m_connect; net_server m_net_server; + std::vector<epee::net_utils::network_address> m_seed_nodes; std::string m_bind_ip; std::string m_bind_ipv6_address; std::string m_port; @@ -212,7 +219,9 @@ namespace nodetool boost::asio::ip::tcp::endpoint m_proxy_address; std::atomic<unsigned int> m_current_number_of_out_peers; std::atomic<unsigned int> m_current_number_of_in_peers; + boost::shared_mutex m_seed_nodes_lock; bool m_can_pingback; + bool m_seed_nodes_initialized; private: void set_config_defaults() noexcept @@ -334,7 +343,7 @@ namespace nodetool virtual void callback(p2p_connection_context& context); //----------------- i_p2p_endpoint ------------------------------------------------------------- virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections); - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay); + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay); virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context); virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context); virtual bool drop_connection(const epee::net_utils::connection_context_base& context); @@ -383,9 +392,10 @@ namespace nodetool void record_addr_failed(const epee::net_utils::network_address& addr); bool is_addr_recently_failed(const epee::net_utils::network_address& addr); bool is_priority_node(const epee::net_utils::network_address& na); - std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const; - std::set<std::string> get_seed_nodes(); - bool connect_to_seed(); + std::set<std::string> get_ip_seed_nodes() const; + std::set<std::string> get_dns_seed_nodes(); + std::set<std::string> get_seed_nodes(epee::net_utils::zone); + bool connect_to_seed(epee::net_utils::zone); template <class Container> bool connect_to_peerlist(const Container& peers); @@ -467,9 +477,6 @@ namespace nodetool std::list<epee::net_utils::network_address> m_priority_peers; std::vector<epee::net_utils::network_address> m_exclusive_peers; - std::vector<epee::net_utils::network_address> m_seed_nodes; - bool m_seed_nodes_initialized = false; - boost::shared_mutex m_seed_nodes_lock; std::atomic_flag m_fallback_seed_nodes_added; std::vector<nodetool::peerlist_entry> m_command_line_peers; uint64_t m_peer_livetime; @@ -523,6 +530,7 @@ namespace nodetool extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node; extern const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy; extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound; + extern const command_line::arg_descriptor<std::string> arg_ban_list; extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port; extern const command_line::arg_descriptor<bool> arg_no_sync; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 175741146..f19865adb 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -106,6 +106,7 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_seed_node); command_line::add_arg(desc, arg_tx_proxy); command_line::add_arg(desc, arg_anonymous_inbound); + command_line::add_arg(desc, arg_ban_list); command_line::add_arg(desc, arg_p2p_hide_my_port); command_line::add_arg(desc, arg_no_sync); command_line::add_arg(desc, arg_no_igd); @@ -245,6 +246,10 @@ namespace nodetool zone.second.m_net_server.get_config_object().close(c); conns.clear(); + + peerlist_entry pe{}; + pe.adr = addr; + zone.second.m_peerlist.remove_from_peer_white(pe); } MCLOG_CYAN(el::Level::Info, "global", "Host " << addr.host_str() << " blocked."); @@ -386,7 +391,7 @@ namespace nodetool m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6); m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4); public_zone.m_notifier = cryptonote::levin::notify{ - public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true, pad_txs + public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core() }; if (command_line::has_arg(vm, arg_p2p_add_peer)) @@ -435,12 +440,42 @@ namespace nodetool if (command_line::has_arg(vm, arg_p2p_seed_node)) { - boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock); + boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock); - if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes)) + if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes)) return false; } + if (!command_line::is_arg_defaulted(vm, arg_ban_list)) + { + const std::string ban_list = command_line::get_arg(vm, arg_ban_list); + + const boost::filesystem::path ban_list_path(ban_list); + boost::system::error_code ec; + if (!boost::filesystem::exists(ban_list_path, ec)) + { + throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message()); + } + + std::string banned_ips; + if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips)) + { + throw std::runtime_error("Failed to read ban list file " + ban_list); + } + + std::istringstream iss(banned_ips); + for (std::string line; std::getline(iss, line); ) + { + const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0); + if (!parsed_addr) + { + MERROR("Invalid IP address: " << line << " - " << parsed_addr.error()); + continue; + } + block_host(*parsed_addr, std::numeric_limits<time_t>::max()); + } + } + if(command_line::has_arg(vm, arg_p2p_hide_my_port)) m_hide_my_port = true; @@ -499,7 +534,7 @@ namespace nodetool } zone.m_notifier = cryptonote::levin::notify{ - zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs + zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core() }; } @@ -598,21 +633,21 @@ namespace nodetool //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const + std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const { std::set<std::string> full_addrs; - if (nettype == cryptonote::TESTNET) + if (m_nettype == cryptonote::TESTNET) { full_addrs.insert("212.83.175.67:28080"); full_addrs.insert("212.83.172.165:28080"); full_addrs.insert("192.110.160.146:28080"); } - else if (nettype == cryptonote::STAGENET) + else if (m_nettype == cryptonote::STAGENET) { full_addrs.insert("162.210.173.150:38080"); full_addrs.insert("192.110.160.146:38080"); } - else if (nettype == cryptonote::FAKECHAIN) + else if (m_nettype == cryptonote::FAKECHAIN) { } else @@ -630,7 +665,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes() + std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes() { if (!m_exclusive_peers.empty() || m_offline) { @@ -638,11 +673,11 @@ namespace nodetool } if (m_nettype == cryptonote::TESTNET) { - return get_seed_nodes(cryptonote::TESTNET); + return get_ip_seed_nodes(); } if (m_nettype == cryptonote::STAGENET) { - return get_seed_nodes(cryptonote::STAGENET); + return get_ip_seed_nodes(); } std::set<std::string> full_addrs; @@ -730,7 +765,7 @@ namespace nodetool else MINFO("Not enough DNS seed nodes found, using fallback defaults too"); - for (const auto &peer: get_seed_nodes(cryptonote::MAINNET)) + for (const auto &peer: get_ip_seed_nodes()) full_addrs.insert(peer); m_fallback_seed_nodes_added.test_and_set(); } @@ -739,6 +774,23 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> + std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone) + { + switch (zone) + { + case epee::net_utils::zone::public_: + return get_dns_seed_nodes(); + case epee::net_utils::zone::tor: + return {}; + case epee::net_utils::zone::i2p: + return {}; + default: + break; + } + throw std::logic_error{"Bad zone given to get_seed_nodes"}; + } + //----------------------------------------------------------------------------------- + template<class t_payload_net_handler> typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone) { const auto zone_ = m_network_zones.lower_bound(zone); @@ -1432,6 +1484,20 @@ namespace nodetool const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); classB.insert(actual_ip & 0x0000ffff); } +#if BOOST_VERSION > 106600 + else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = cntxt.m_remote_address; + const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + classB.insert(actual_ipv4 & ntohl(0xffff0000)); + } + } +#endif return true; }); } @@ -1452,6 +1518,20 @@ namespace nodetool uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); skip = classB.find(actual_ip & 0x0000ffff) != classB.end(); } +#if BOOST_VERSION > 106600 + else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = pe.adr; + const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end(); + } + } +#endif if (skip) ++skipped; else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0) @@ -1464,11 +1544,11 @@ namespace nodetool if (skipped == 0 || !filtered.empty()) break; if (skipped) - MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers"); + MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers"); } if (filtered.empty()) { - MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); + MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); return false; } if (use_white_list) @@ -1541,56 +1621,59 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::connect_to_seed() + bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone) { - boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock); + network_zone& server = m_network_zones.at(zone); + boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock); - if (!m_seed_nodes_initialized) + if (!server.m_seed_nodes_initialized) { + const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT; boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock); - m_seed_nodes_initialized = true; - for (const auto& full_addr : get_seed_nodes()) + server.m_seed_nodes_initialized = true; + for (const auto& full_addr : get_seed_nodes(zone)) { + // seeds should have hostname converted to IP already MDEBUG("Seed node: " << full_addr); - append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); + server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port))); } - MDEBUG("Number of seed nodes: " << m_seed_nodes.size()); + MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size()); } - if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty()) + if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty()) return true; size_t try_count = 0; bool is_connected_to_at_least_one_seed_node = false; - size_t current_index = crypto::rand_idx(m_seed_nodes.size()); - const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server; + size_t current_index = crypto::rand_idx(server.m_seed_nodes.size()); while(true) { - if(server.is_stop_signal_sent()) + if(server.m_net_server.is_stop_signal_sent()) return false; peerlist_entry pe_seed{}; - pe_seed.adr = m_seed_nodes[current_index]; + pe_seed.adr = server.m_seed_nodes[current_index]; if (is_peer_used(pe_seed)) is_connected_to_at_least_one_seed_node = true; - else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true)) + else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true)) break; - if(++try_count > m_seed_nodes.size()) + if(++try_count > server.m_seed_nodes.size()) { - if (!m_fallback_seed_nodes_added.test_and_set()) + // only IP zone has fallback (to direct IP) seeds + if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set()) { MWARNING("Failed to connect to any of seed peers, trying fallback seeds"); - current_index = m_seed_nodes.size() - 1; + current_index = server.m_seed_nodes.size() - 1; { boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock); - for (const auto &peer: get_seed_nodes(m_nettype)) + for (const auto &peer: get_ip_seed_nodes()) { MDEBUG("Fallback seed node: " << peer); - append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); + append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); } } - if (current_index == m_seed_nodes.size() - 1) + if (current_index == server.m_seed_nodes.size() - 1) { MWARNING("No fallback seeds, continuing without seeds"); break; @@ -1604,7 +1687,7 @@ namespace nodetool break; } } - if(++current_index >= m_seed_nodes.size()) + if(++current_index >= server.m_seed_nodes.size()) current_index = 0; } return true; @@ -1620,20 +1703,21 @@ namespace nodetool if (!m_exclusive_peers.empty()) return true; - // Only have seeds in the public zone right now. - - size_t start_conn_count = get_public_outgoing_connections_count(); - if(!get_public_white_peers_count() && !connect_to_seed()) + bool one_succeeded = false; + for(auto& zone : m_network_zones) { - return false; - } + size_t start_conn_count = get_outgoing_connections_count(zone.second); + if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first)) + { + continue; + } - if (!connect_to_peerlist(m_priority_peers)) return false; + if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue; - for(auto& zone : m_network_zones) - { size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; + // carefully avoid `continue` in nested loop + size_t conn_count = get_outgoing_connections_count(zone.second); while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count) { @@ -1670,16 +1754,17 @@ namespace nodetool } conn_count = new_conn_count; } - } - if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count) - { - MINFO("Failed to connect to any, trying seeds"); - if (!connect_to_seed()) - return false; + if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count) + { + MINFO("Failed to connect to any, trying seeds"); + if (!connect_to_seed(zone.first)) + continue; + } + one_succeeded = true; } - return true; + return one_succeeded; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> @@ -1994,13 +2079,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const cryptonote::relay_method tx_relay) + epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const cryptonote::relay_method tx_relay) { namespace enet = epee::net_utils; - const auto send = [&txs, &source, &core, tx_relay] (std::pair<const enet::zone, network_zone>& network) + const auto send = [&txs, &source, tx_relay] (std::pair<const enet::zone, network_zone>& network) { - if (network.second.m_notifier.send_txs(std::move(txs), source, core, tx_relay)) + if (network.second.m_notifier.send_txs(std::move(txs), source, tx_relay)) return network.first; return enet::zone::invalid; }; @@ -2095,7 +2180,7 @@ namespace nodetool const epee::net_utils::network_address na = context.m_remote_address; std::string ip; - uint32_t ipv4_addr; + uint32_t ipv4_addr = 0; boost::asio::ip::address_v6 ipv6_addr; bool is_ipv4; if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 393d38e0a..2ace5987f 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -50,7 +50,7 @@ namespace nodetool struct i_p2p_endpoint { virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0; - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay)=0; + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay)=0; virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0; virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0; virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; @@ -75,7 +75,7 @@ namespace nodetool { return false; } - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay) + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay) { return epee::net_utils::zone::invalid; } diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index e073bb61b..00b72123a 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -368,6 +368,12 @@ namespace rct { template<bool W, template <bool> class Archive> bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin) { + if (inputs >= 0xffffffff) + return false; + if (outputs >= 0xffffffff) + return false; + if (mixin >= 0xffffffff) + return false; if (type == RCTTypeNull) return ar.stream().good(); if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG) diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 19298c969..aa4102481 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -66,7 +66,7 @@ set(rpc_pub_headers zmq_pub.h) set(daemon_rpc_server_headers) -set(rpc_daemon_private_headers +set(rpc_private_headers bootstrap_daemon.h core_rpc_server.h rpc_payment.h diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index a50c70418..fc67e2dd1 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -521,9 +521,17 @@ namespace cryptonote bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, const connection_context *ctx) { RPC_TRACKER(get_blocks); - bool r; - if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r)) - return r; + + bool use_bootstrap_daemon; + { + boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); + use_bootstrap_daemon = m_should_use_bootstrap_daemon; + } + if (use_bootstrap_daemon) + { + bool r; + return use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r); + } CHECK_PAYMENT(req, res, 1); @@ -1123,13 +1131,18 @@ namespace cryptonote { RPC_TRACKER(send_raw_tx); + { + bool ok; + use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok); + } + const bool restricted = m_restricted && ctx; bool skip_validation = false; if (!restricted) { boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); - if (m_bootstrap_daemon.get() != nullptr) + if (m_should_use_bootstrap_daemon) { skip_validation = !check_core_ready(); } @@ -1138,6 +1151,10 @@ namespace cryptonote CHECK_CORE_READY(); } } + else + { + CHECK_CORE_READY(); + } CHECK_PAYMENT_MIN1(req, res, COST_PER_TX_RELAY, false); @@ -1661,6 +1678,13 @@ namespace cryptonote return false; } + uint64_t next_height; + crypto::rx_seedheights(height, &seed_height, &next_height); + if (next_height != seed_height) + next_seed_hash = m_core.get_block_id_by_height(next_height); + else + next_seed_hash = seed_hash; + if (extra_nonce.empty()) { reserved_offset = 0; @@ -2812,6 +2836,8 @@ namespace cryptonote RPC_TRACKER(relay_tx); CHECK_PAYMENT_MIN1(req, res, req.txids.size() * COST_PER_TX_RELAY, false); + const bool restricted = m_restricted && ctx; + bool failed = false; res.status = ""; for (const auto &str: req.txids) @@ -2825,12 +2851,16 @@ namespace cryptonote continue; } + //TODO: The get_pool_transaction could have an optional meta parameter + bool broadcasted = false; cryptonote::blobdata txblob; - if (m_core.get_pool_transaction(txid, txblob, relay_category::legacy)) + if ((broadcasted = m_core.get_pool_transaction(txid, txblob, relay_category::broadcasted)) || (!restricted && m_core.get_pool_transaction(txid, txblob, relay_category::all))) { + // The settings below always choose i2p/tor if enabled. Otherwise, do fluff iff previously relayed else dandelion++ stem. NOTIFY_NEW_TRANSACTIONS::request r; r.txs.push_back(std::move(txblob)); - m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, relay_method::local); + const auto tx_relay = broadcasted ? relay_method::fluff : relay_method::local; + m_core.get_protocol()->relay_transactions(r, boost::uuids::nil_uuid(), epee::net_utils::zone::invalid, tx_relay); //TODO: make sure that tx has reached other nodes here, probably wait to receive reflections from other nodes } else diff --git a/src/rpc/zmq_pub.cpp b/src/rpc/zmq_pub.cpp index 0dffffac6..eac530968 100644 --- a/src/rpc/zmq_pub.cpp +++ b/src/rpc/zmq_pub.cpp @@ -221,7 +221,7 @@ namespace void add_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first) { assert(range.size() <= N); - assert(range.begin() - first <= N - range.size()); + assert((unsigned long)(range.begin() - first) <= N - range.size()); for (const auto& ctx : range) { @@ -234,7 +234,7 @@ namespace void remove_subscriptions(std::array<std::size_t, N>& subs, const epee::span<const context<T>> range, context<T> const* const first) { assert(range.size() <= N); - assert(range.begin() - first <= N - range.size()); + assert((unsigned long)(range.begin() - first) <= N - range.size()); for (const auto& ctx : range) { diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp index f69a69ca3..96090d9f5 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -70,6 +70,25 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa return r; } +bool AddressBookImpl::setDescription(std::size_t index, const std::string &description) +{ + clearStatus(); + + const auto ab = m_wallet->m_wallet->get_address_book(); + if (index >= ab.size()){ + return false; + } + + tools::wallet2::address_book_row entry = ab[index]; + entry.m_description = description; + bool r = m_wallet->m_wallet->set_address_book_row(index, entry.m_address, NULL, entry.m_description, entry.m_is_subaddress); + if (r) + refresh(); + else + m_errorCode = General_Error; + return r; +} + void AddressBookImpl::refresh() { LOG_PRINT_L2("Refreshing addressbook"); diff --git a/src/wallet/api/address_book.h b/src/wallet/api/address_book.h index f287969f3..e22f474fb 100644 --- a/src/wallet/api/address_book.h +++ b/src/wallet/api/address_book.h @@ -45,6 +45,7 @@ public: void refresh() override; std::vector<AddressBookRow*> getAll() const override; bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) override; + bool setDescription(std::size_t index, const std::string &description) override; bool deleteRow(std::size_t rowId) override; // Error codes. See AddressBook:ErrorCode enum in wallet2_api.h diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index bcb300889..b6d52c58d 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -92,6 +92,17 @@ std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const return m_history; } +void TransactionHistoryImpl::setTxNote(const std::string &txid, const std::string ¬e) +{ + cryptonote::blobdata txid_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash)) + return; + const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data()); + + m_wallet->m_wallet->set_tx_note(htxid, note); + refresh(); +} + void TransactionHistoryImpl::refresh() { // multithreaded access: @@ -126,10 +137,12 @@ void TransactionHistoryImpl::refresh() payment_id = payment_id.substr(0,16); TransactionInfoImpl * ti = new TransactionInfoImpl(); ti->m_paymentid = payment_id; + ti->m_coinbase = pd.m_coinbase; ti->m_amount = pd.m_amount; ti->m_direction = TransactionInfo::Direction_In; ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash); ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrAccount = pd.m_subaddr_index.major; ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); @@ -173,6 +186,7 @@ void TransactionHistoryImpl::refresh() ti->m_direction = TransactionInfo::Direction_Out; ti->m_hash = string_tools::pod_to_hex(hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(hash); ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; @@ -183,6 +197,7 @@ void TransactionHistoryImpl::refresh() for (const auto &d: pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); } + m_history.push_back(ti); } @@ -207,11 +222,16 @@ void TransactionHistoryImpl::refresh() ti->m_failed = is_failed; ti->m_pending = true; ti->m_hash = string_tools::pod_to_hex(hash); + ti->m_description = m_wallet->m_wallet->get_tx_note(hash); ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_timestamp = pd.m_timestamp; ti->m_confirmations = 0; + for (const auto &d : pd.m_dests) + { + ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); + } m_history.push_back(ti); } @@ -230,6 +250,7 @@ void TransactionHistoryImpl::refresh() ti->m_direction = TransactionInfo::Direction_In; ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash); ti->m_pending = true; ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrAccount = pd.m_subaddr_index.major; diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index 8f3805788..60f12d771 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -45,6 +45,7 @@ public: virtual TransactionInfo * transaction(const std::string &id) const; virtual std::vector<TransactionInfo*> getAll() const; virtual void refresh(); + virtual void setTxNote(const std::string &txid, const std::string ¬e); private: diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 5ae3a6937..33e7856db 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -45,6 +45,7 @@ TransactionInfoImpl::TransactionInfoImpl() : m_direction(Direction_Out) , m_pending(false) , m_failed(false) + , m_coinbase(false) , m_amount(0) , m_fee(0) , m_blockheight(0) @@ -77,6 +78,11 @@ bool TransactionInfoImpl::isFailed() const return m_failed; } +bool TransactionInfoImpl::isCoinbase() const +{ + return m_coinbase; +} + uint64_t TransactionInfoImpl::amount() const { return m_amount; @@ -92,6 +98,11 @@ uint64_t TransactionInfoImpl::blockHeight() const return m_blockheight; } +std::string TransactionInfoImpl::description() const +{ + return m_description; +} + std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const { return m_subaddrIndex; diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 73bb7689d..8bc36a8e9 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -46,10 +46,12 @@ public: //! true if hold virtual bool isPending() const override; virtual bool isFailed() const override; + virtual bool isCoinbase() const override; virtual uint64_t amount() const override; //! always 0 for incoming txes virtual uint64_t fee() const override; virtual uint64_t blockHeight() const override; + virtual std::string description() const override; virtual std::set<uint32_t> subaddrIndex() const override; virtual uint32_t subaddrAccount() const override; virtual std::string label() const override; @@ -65,9 +67,11 @@ private: int m_direction; bool m_pending; bool m_failed; + bool m_coinbase; uint64_t m_amount; uint64_t m_fee; uint64_t m_blockheight; + std::string m_description; std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers uint32_t m_subaddrAccount; std::string m_label; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 152a7dcd7..9acc8484c 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -910,6 +910,11 @@ std::string WalletImpl::path() const return m_wallet->path(); } +void WalletImpl::stop() +{ + m_wallet->stop(); +} + bool WalletImpl::store(const std::string &path) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index caf1e9ed4..3bf3e759b 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -99,6 +99,7 @@ public: std::string publicSpendKey() const override; std::string publicMultisigSignerKey() const override; std::string path() const override; + void stop() override; bool store(const std::string &path) override; std::string filename() const override; std::string keysFilename() const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 50df7e5dd..44928a422 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -182,9 +182,11 @@ struct TransactionInfo virtual int direction() const = 0; virtual bool isPending() const = 0; virtual bool isFailed() const = 0; + virtual bool isCoinbase() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; virtual uint64_t blockHeight() const = 0; + virtual std::string description() const = 0; virtual std::set<uint32_t> subaddrIndex() const = 0; virtual uint32_t subaddrAccount() const = 0; virtual std::string label() const = 0; @@ -208,6 +210,7 @@ struct TransactionHistory virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector<TransactionInfo*> getAll() const = 0; virtual void refresh() = 0; + virtual void setTxNote(const std::string &txid, const std::string ¬e) = 0; }; /** @@ -250,6 +253,7 @@ struct AddressBook virtual std::vector<AddressBookRow*> getAll() const = 0; virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; virtual bool deleteRow(std::size_t rowId) = 0; + virtual bool setDescription(std::size_t index, const std::string &description) = 0; virtual void refresh() = 0; virtual std::string errorString() const = 0; virtual int errorCode() const = 0; @@ -507,6 +511,11 @@ struct Wallet virtual std::string publicMultisigSignerKey() const = 0; /*! + * \brief stop - interrupts wallet refresh() loop once (doesn't stop background refresh thread) + */ + virtual void stop() = 0; + + /*! * \brief store - stores wallet to file. * \param path - main filename to store wallet to. additionally stores address file and keys file. * to store to the same file - just pass empty string; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 949e2d451..30d06c20c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2962,6 +2962,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, MTRACE("update_pool_state got pool"); // remove any pending tx that's not in the pool + constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2}; + const auto now = std::chrono::system_clock::now(); std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin(); while (it != m_unconfirmed_txs.end()) { @@ -2989,9 +2991,11 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as not in pool"); pit->second.m_state = wallet2::unconfirmed_transfer_details::pending_not_in_pool; } - else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed) + else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed && + now > std::chrono::system_clock::from_time_t(pit->second.m_sent_time) + tx_propagation_timeout) { - LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as failed"); + LOG_PRINT_L1("Pending txid " << txid << " not in pool after " << tx_propagation_timeout.count() << + " seconds, marking as failed"); pit->second.m_state = wallet2::unconfirmed_transfer_details::failed; // the inputs aren't spent anymore, since the tx failed @@ -13064,6 +13068,8 @@ process: crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); + THROW_WALLET_EXCEPTION_IF(td.m_internal_output_index >= td.m_tx.vout.size(), + error::wallet_internal_error, "Internal index is out of range"); THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key), error::wallet_internal_error, "Unsupported output type"); const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1c9cca9d8..68f03db72 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -434,7 +434,7 @@ private: std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> m_rings; // relative BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) FIELD(m_tx) VARINT_FIELD(m_amount_in) VARINT_FIELD(m_amount_out) @@ -442,6 +442,8 @@ private: VARINT_FIELD(m_sent_time) FIELD(m_dests) FIELD(m_payment_id) + if (version >= 1) + VARINT_FIELD(m_state) VARINT_FIELD(m_timestamp) VARINT_FIELD(m_subaddr_account) FIELD(m_subaddr_indices) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c601b93ed..224784a18 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -106,7 +106,7 @@ set(hash_targets_sources set(hash_targets_headers) -add_executable(hash-target-tests +monero_add_minimal_executable(hash-target-tests ${hash_targets_sources} ${hash_targets_headers}) target_link_libraries(hash-target-tests @@ -149,7 +149,7 @@ foreach(BENCH IN LISTS MONERO_WALLET_CRYPTO_BENCH) endforeach () configure_file("${CMAKE_CURRENT_SOURCE_DIR}/benchmark.h.in" "${MONERO_GENERATED_HEADERS_DIR}/tests/benchmark.h") -add_executable(monero-wallet-crypto-bench benchmark.cpp ${BENCH_OBJECTS}) +monero_add_minimal_executable(monero-wallet-crypto-bench benchmark.cpp ${BENCH_OBJECTS}) target_link_libraries(monero-wallet-crypto-bench cncrypto) add_test(NAME wallet-crypto-bench COMMAND monero-wallet-crypto-bench) diff --git a/tests/block_weight/CMakeLists.txt b/tests/block_weight/CMakeLists.txt index a59c9c1fc..9bde90be4 100644 --- a/tests/block_weight/CMakeLists.txt +++ b/tests/block_weight/CMakeLists.txt @@ -31,7 +31,7 @@ set(block_weight_sources set(block_weight_headers) -add_executable(block_weight +monero_add_minimal_executable(block_weight ${block_weight_sources} ${block_weight_headers}) target_link_libraries(block_weight diff --git a/tests/core_proxy/CMakeLists.txt b/tests/core_proxy/CMakeLists.txt index 7896389f2..63c511665 100644 --- a/tests/core_proxy/CMakeLists.txt +++ b/tests/core_proxy/CMakeLists.txt @@ -32,7 +32,7 @@ set(core_proxy_sources set(core_proxy_headers core_proxy.h) -add_executable(core_proxy +monero_add_minimal_executable(core_proxy ${core_proxy_sources} ${core_proxy_headers}) target_link_libraries(core_proxy diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 4a41b5002..ecfcc18ae 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -66,9 +66,10 @@ namespace tests public: + virtual bool is_synchronized() const final { return true; } void on_synchronized(){} void safesyncmode(const bool){} - uint64_t get_current_blockchain_height(){return 1;} + virtual uint64_t get_current_blockchain_height() const final {return 1;} void set_target_blockchain_height(uint64_t) {} bool init(const boost::program_options::variables_map& vm); bool deinit(){return true;} diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index 654233d03..7455639ca 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -68,7 +68,7 @@ set(core_tests_headers rct2.h wallet_tools.h) -add_executable(core_tests +monero_add_minimal_executable(core_tests ${core_tests_sources} ${core_tests_headers}) target_link_libraries(core_tests diff --git a/tests/crypto/CMakeLists.txt b/tests/crypto/CMakeLists.txt index dcf5d8fb0..c8ea5a604 100644 --- a/tests/crypto/CMakeLists.txt +++ b/tests/crypto/CMakeLists.txt @@ -37,7 +37,7 @@ set(crypto_sources set(crypto_headers crypto-tests.h) -add_executable(cncrypto-tests +monero_add_minimal_executable(cncrypto-tests ${crypto_sources} ${crypto_headers}) target_link_libraries(cncrypto-tests @@ -53,7 +53,7 @@ add_test( NAME cncrypto COMMAND cncrypto-tests "${CMAKE_CURRENT_SOURCE_DIR}/tests.txt") -add_executable(cnv4-jit-tests cnv4-jit.c) +monero_add_minimal_executable(cnv4-jit-tests cnv4-jit.c) target_link_libraries(cnv4-jit-tests PRIVATE common diff --git a/tests/daemon_tests/CMakeLists.txt b/tests/daemon_tests/CMakeLists.txt index 7735b5ecb..a3fce119d 100644 --- a/tests/daemon_tests/CMakeLists.txt +++ b/tests/daemon_tests/CMakeLists.txt @@ -31,7 +31,7 @@ set(transfers_sources set(transfers_headers) -add_executable(transfers +monero_add_minimal_executable(transfers ${transfers_sources} ${transfers_headers}) target_link_libraries(transfers diff --git a/tests/difficulty/CMakeLists.txt b/tests/difficulty/CMakeLists.txt index c5c3bfb02..231038440 100644 --- a/tests/difficulty/CMakeLists.txt +++ b/tests/difficulty/CMakeLists.txt @@ -31,7 +31,7 @@ set(difficulty_sources set(difficulty_headers) -add_executable(difficulty-tests +monero_add_minimal_executable(difficulty-tests ${difficulty_sources} ${difficulty_headers}) target_link_libraries(difficulty-tests diff --git a/tests/functional_tests/CMakeLists.txt b/tests/functional_tests/CMakeLists.txt index 6972be55f..462fd4b77 100644 --- a/tests/functional_tests/CMakeLists.txt +++ b/tests/functional_tests/CMakeLists.txt @@ -35,7 +35,7 @@ set(functional_tests_headers transactions_flow_test.h transactions_generation_from_blockchain.h) -add_executable(functional_tests +monero_add_minimal_executable(functional_tests ${functional_tests_sources} ${functional_tests_headers}) target_link_libraries(functional_tests @@ -53,7 +53,7 @@ target_link_libraries(functional_tests set(make_test_signature_sources make_test_signature.cc) -add_executable(make_test_signature +monero_add_minimal_executable(make_test_signature ${make_test_signature_sources}) target_link_libraries(make_test_signature diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py index c60bf8396..1eb6b0ba7 100755 --- a/tests/functional_tests/mining.py +++ b/tests/functional_tests/mining.py @@ -95,20 +95,19 @@ class MiningTest(): assert res_status.block_reward >= 600000000000 # wait till we mined a few of them + target_height = prev_height + 5 + height = prev_height timeout = 60 # randomx is slow to init - timeout_height = prev_height - while True: - time.sleep(1) - res_info = daemon.get_info() - height = res_info.height - if height >= prev_height + 5: - break - if height > timeout_height: - timeout = 5 - timeout_height = height + while height < target_height: + seen_height = height + for _ in range(timeout): + time.sleep(1) + height = daemon.get_info().height + if height > seen_height: + break else: - timeout -= 1 - assert timeout >= 0 + assert False, 'Failed to mine successor to block %d (initial block = %d)' % (seen_height, prev_height) + timeout = 10 if via_daemon: res = daemon.stop_mining() diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt index 48a49edab..a599f86f8 100644 --- a/tests/fuzz/CMakeLists.txt +++ b/tests/fuzz/CMakeLists.txt @@ -26,7 +26,7 @@ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -add_executable(block_fuzz_tests block.cpp fuzzer.cpp) +monero_add_minimal_executable(block_fuzz_tests block.cpp fuzzer.cpp) target_link_libraries(block_fuzz_tests PRIVATE cryptonote_core @@ -40,7 +40,7 @@ set_property(TARGET block_fuzz_tests PROPERTY FOLDER "tests") -add_executable(transaction_fuzz_tests transaction.cpp fuzzer.cpp) +monero_add_minimal_executable(transaction_fuzz_tests transaction.cpp fuzzer.cpp) target_link_libraries(transaction_fuzz_tests PRIVATE cryptonote_core @@ -54,7 +54,7 @@ set_property(TARGET transaction_fuzz_tests PROPERTY FOLDER "tests") -add_executable(signature_fuzz_tests signature.cpp fuzzer.cpp) +monero_add_minimal_executable(signature_fuzz_tests signature.cpp fuzzer.cpp) target_link_libraries(signature_fuzz_tests PRIVATE wallet @@ -69,7 +69,7 @@ set_property(TARGET signature_fuzz_tests PROPERTY FOLDER "tests") -add_executable(cold-outputs_fuzz_tests cold-outputs.cpp fuzzer.cpp) +monero_add_minimal_executable(cold-outputs_fuzz_tests cold-outputs.cpp fuzzer.cpp) target_link_libraries(cold-outputs_fuzz_tests PRIVATE wallet @@ -84,7 +84,7 @@ set_property(TARGET cold-outputs_fuzz_tests PROPERTY FOLDER "tests") -add_executable(cold-transaction_fuzz_tests cold-transaction.cpp fuzzer.cpp) +monero_add_minimal_executable(cold-transaction_fuzz_tests cold-transaction.cpp fuzzer.cpp) target_link_libraries(cold-transaction_fuzz_tests PRIVATE wallet @@ -99,7 +99,7 @@ set_property(TARGET cold-transaction_fuzz_tests PROPERTY FOLDER "tests") -add_executable(load-from-binary_fuzz_tests load_from_binary.cpp fuzzer.cpp) +monero_add_minimal_executable(load-from-binary_fuzz_tests load_from_binary.cpp fuzzer.cpp) target_link_libraries(load-from-binary_fuzz_tests PRIVATE common @@ -112,7 +112,7 @@ set_property(TARGET load-from-binary_fuzz_tests PROPERTY FOLDER "tests") -add_executable(load-from-json_fuzz_tests load_from_json.cpp fuzzer.cpp) +monero_add_minimal_executable(load-from-json_fuzz_tests load_from_json.cpp fuzzer.cpp) target_link_libraries(load-from-json_fuzz_tests PRIVATE common @@ -125,7 +125,7 @@ set_property(TARGET load-from-json_fuzz_tests PROPERTY FOLDER "tests") -add_executable(base58_fuzz_tests base58.cpp fuzzer.cpp) +monero_add_minimal_executable(base58_fuzz_tests base58.cpp fuzzer.cpp) target_link_libraries(base58_fuzz_tests PRIVATE common @@ -138,7 +138,7 @@ set_property(TARGET base58_fuzz_tests PROPERTY FOLDER "tests") -add_executable(parse-url_fuzz_tests parse_url.cpp fuzzer.cpp) +monero_add_minimal_executable(parse-url_fuzz_tests parse_url.cpp fuzzer.cpp) target_link_libraries(parse-url_fuzz_tests PRIVATE epee @@ -152,7 +152,7 @@ set_property(TARGET parse-url_fuzz_tests PROPERTY FOLDER "tests") -add_executable(http-client_fuzz_tests http-client.cpp fuzzer.cpp) +monero_add_minimal_executable(http-client_fuzz_tests http-client.cpp fuzzer.cpp) target_link_libraries(http-client_fuzz_tests PRIVATE epee @@ -168,7 +168,7 @@ set_property(TARGET http-client_fuzz_tests PROPERTY FOLDER "tests") -add_executable(levin_fuzz_tests levin.cpp fuzzer.cpp) +monero_add_minimal_executable(levin_fuzz_tests levin.cpp fuzzer.cpp) target_link_libraries(levin_fuzz_tests PRIVATE common @@ -184,7 +184,7 @@ set_property(TARGET levin_fuzz_tests PROPERTY FOLDER "tests") -add_executable(bulletproof_fuzz_tests bulletproof.cpp fuzzer.cpp) +monero_add_minimal_executable(bulletproof_fuzz_tests bulletproof.cpp fuzzer.cpp) target_link_libraries(bulletproof_fuzz_tests PRIVATE common @@ -200,7 +200,7 @@ set_property(TARGET bulletproof_fuzz_tests PROPERTY FOLDER "tests") -add_executable(tx-extra_fuzz_tests tx-extra.cpp fuzzer.cpp) +monero_add_minimal_executable(tx-extra_fuzz_tests tx-extra.cpp fuzzer.cpp) target_link_libraries(tx-extra_fuzz_tests PRIVATE cryptonote_basic diff --git a/tests/fuzz/signature.cpp b/tests/fuzz/signature.cpp index c587ff6cd..443057a57 100644 --- a/tests/fuzz/signature.cpp +++ b/tests/fuzz/signature.cpp @@ -59,6 +59,6 @@ BEGIN_INIT_SIMPLE_FUZZER() END_INIT_SIMPLE_FUZZER() BEGIN_SIMPLE_FUZZER() - tools::wallet2::message_signature_result_t result = wallet->verify("test", address, s); + tools::wallet2::message_signature_result_t result = wallet->verify("test", address, std::string((const char*)buf, len)); std::cout << "Signature " << (result.valid ? "valid" : "invalid") << std::endl; END_SIMPLE_FUZZER() diff --git a/tests/hash/CMakeLists.txt b/tests/hash/CMakeLists.txt index 91dfdff1e..1d7d4cc5e 100644 --- a/tests/hash/CMakeLists.txt +++ b/tests/hash/CMakeLists.txt @@ -31,7 +31,7 @@ set(hash_sources set(hash_headers) -add_executable(hash-tests +monero_add_minimal_executable(hash-tests ${hash_sources} ${hash_headers}) target_link_libraries(hash-tests diff --git a/tests/libwallet_api_tests/CMakeLists.txt b/tests/libwallet_api_tests/CMakeLists.txt index 8d03399fa..1c7a7cae4 100644 --- a/tests/libwallet_api_tests/CMakeLists.txt +++ b/tests/libwallet_api_tests/CMakeLists.txt @@ -33,7 +33,7 @@ set(libwallet_api_tests_sources set(libwallet_api_tests_headers ) -add_executable(libwallet_api_tests +monero_add_minimal_executable(libwallet_api_tests ${libwallet_api_tests_sources} ${libwallet_api_tests_headers}) diff --git a/tests/net_load_tests/CMakeLists.txt b/tests/net_load_tests/CMakeLists.txt index 9bcc2d6ab..c334df4ba 100644 --- a/tests/net_load_tests/CMakeLists.txt +++ b/tests/net_load_tests/CMakeLists.txt @@ -32,7 +32,7 @@ set(clt_sources set(clt_headers net_load_tests.h) -add_executable(net_load_tests_clt +monero_add_minimal_executable(net_load_tests_clt ${clt_sources} ${clt_headers}) target_link_libraries(net_load_tests_clt @@ -54,7 +54,7 @@ set(srv_sources set(srv_headers net_load_tests.h) -add_executable(net_load_tests_srv +monero_add_minimal_executable(net_load_tests_srv ${srv_sources} ${srv_headers}) target_link_libraries(net_load_tests_srv diff --git a/tests/performance_tests/CMakeLists.txt b/tests/performance_tests/CMakeLists.txt index 1a9da116f..542d204e0 100644 --- a/tests/performance_tests/CMakeLists.txt +++ b/tests/performance_tests/CMakeLists.txt @@ -55,7 +55,7 @@ set(performance_tests_headers performance_utils.h single_tx_test_base.h) -add_executable(performance_tests +monero_add_minimal_executable(performance_tests ${performance_tests_sources} ${performance_tests_headers}) target_link_libraries(performance_tests diff --git a/tests/trezor/CMakeLists.txt b/tests/trezor/CMakeLists.txt index 15ed5668d..382d8e46f 100644 --- a/tests/trezor/CMakeLists.txt +++ b/tests/trezor/CMakeLists.txt @@ -40,7 +40,7 @@ set(trezor_tests_headers ../core_tests/chaingen.h ../core_tests/wallet_tools.h) -add_executable(trezor_tests +monero_add_minimal_executable(trezor_tests ${trezor_tests_sources} ${trezor_tests_headers}) diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index a5984b2c9..33ef93288 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -101,7 +101,7 @@ set(unit_tests_sources set(unit_tests_headers unit_tests_utils.h) -add_executable(unit_tests +monero_add_minimal_executable(unit_tests ${unit_tests_sources} ${unit_tests_headers}) target_link_libraries(unit_tests @@ -144,6 +144,6 @@ add_test( NAME unit_tests COMMAND unit_tests --data-dir "${TEST_DATA_DIR}") -add_executable(test_notifier test_notifier.cpp) +monero_add_minimal_executable(test_notifier test_notifier.cpp) target_link_libraries(test_notifier ${EXTRA_LIBRARIES}) set_property(TARGET test_notifier PROPERTY FOLDER "tests") diff --git a/tests/unit_tests/block_reward.cpp b/tests/unit_tests/block_reward.cpp index 5f3335981..2f0ea92f3 100644 --- a/tests/unit_tests/block_reward.cpp +++ b/tests/unit_tests/block_reward.cpp @@ -138,24 +138,6 @@ namespace ASSERT_FALSE(m_block_not_too_big); } -#ifdef __x86_64__ // For 64-bit systems only, because block size is limited to size_t. - TEST_F(block_reward_and_current_block_weight, fails_on_huge_median_size) - { -#if !defined(NDEBUG) - size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2); - ASSERT_DEATH(do_test(huge_size, huge_size + 1), ""); -#endif - } - - TEST_F(block_reward_and_current_block_weight, fails_on_huge_block_weight) - { -#if !defined(NDEBUG) - size_t huge_size = std::numeric_limits<uint32_t>::max() + UINT64_C(2); - ASSERT_DEATH(do_test(huge_size - 2, huge_size), ""); -#endif - } -#endif // __x86_64__ - //-------------------------------------------------------------------------------------------------------------------- class block_reward_and_last_block_weights : public ::testing::Test { diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp index 15563e764..22638942d 100644 --- a/tests/unit_tests/levin.cpp +++ b/tests/unit_tests/levin.cpp @@ -120,6 +120,16 @@ namespace { std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_; + virtual bool is_synchronized() const final + { + return false; + } + + virtual uint64_t get_current_blockchain_height() const final + { + return 0; + } + virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> txes, cryptonote::relay_method relay) override final { std::vector<cryptonote::blobdata>& cached = relayed_[relay]; @@ -324,7 +334,8 @@ namespace epee::byte_slice noise = nullptr; if (noise_size) noise = epee::levin::make_noise_notify(noise_size); - return cryptonote::levin::notify{io_service_, connections_, std::move(noise), is_public, pad_txs}; + epee::net_utils::zone zone = is_public ? epee::net_utils::zone::public_ : epee::net_utils::zone::i2p; + return cryptonote::levin::notify{io_service_, connections_, std::move(noise), zone, pad_txs, events_}; } boost::uuids::random_generator random_generator_; @@ -483,11 +494,11 @@ TEST_F(levin_notify, defaulted) EXPECT_FALSE(status.has_noise); EXPECT_FALSE(status.connections_filled); } - EXPECT_TRUE(notifier.send_txs({}, random_generator_(), events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs({}, random_generator_(), cryptonote::relay_method::local)); std::vector<cryptonote::blobdata> txs(2); txs[0].resize(100, 'e'); - EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_(), events_, cryptonote::relay_method::local)); + EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_(), cryptonote::relay_method::local)); } TEST_F(levin_notify, fluff_without_padding) @@ -512,7 +523,7 @@ TEST_F(levin_notify, fluff_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -564,7 +575,7 @@ TEST_F(levin_notify, stem_without_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -608,6 +619,61 @@ TEST_F(levin_notify, stem_without_padding) } } +TEST_F(levin_notify, stem_no_outs_without_padding) +{ + cryptonote::levin::notify notifier = make_notifier(0, true, false); + + for (unsigned count = 0; count < 10; ++count) + add_connection(true); + + { + const auto status = notifier.get_status(); + EXPECT_FALSE(status.has_noise); + EXPECT_FALSE(status.connections_filled); + } + notifier.new_out_connection(); + io_service_.poll(); + + std::vector<cryptonote::blobdata> txs(2); + txs[0].resize(100, 'f'); + txs[1].resize(200, 'e'); + + std::vector<cryptonote::blobdata> sorted_txs = txs; + std::sort(sorted_txs.begin(), sorted_txs.end()); + + ASSERT_EQ(10u, contexts_.size()); + + auto context = contexts_.begin(); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); + + io_service_.reset(); + ASSERT_LT(0u, io_service_.poll()); + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff)); + if (events_.has_stem_txes()) + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem)); + + + notifier.run_fluff(); + ASSERT_LT(0u, io_service_.poll()); + + std::size_t send_count = 0; + EXPECT_EQ(0u, context->process_send_queue()); + for (++context; context != contexts_.end(); ++context) + { + send_count += context->process_send_queue(); + } + + EXPECT_EQ(9u, send_count); + ASSERT_EQ(9u, receiver_.notified_size()); + for (unsigned count = 0; count < 9u; ++count) + { + auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second; + EXPECT_EQ(sorted_txs, notification.txs); + EXPECT_TRUE(notification._.empty()); + EXPECT_TRUE(notification.dandelionpp_fluff); + } +} + TEST_F(levin_notify, local_without_padding) { cryptonote::levin::notify notifier = make_notifier(0, true, false); @@ -636,7 +702,7 @@ TEST_F(levin_notify, local_without_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -708,7 +774,7 @@ TEST_F(levin_notify, forward_without_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -727,7 +793,9 @@ TEST_F(levin_notify, forward_without_padding) { const std::size_t sent = context->process_send_queue(); if (sent && is_stem) + { EXPECT_EQ(1u, (context - contexts_.begin()) % 2); + } send_count += sent; } @@ -772,7 +840,7 @@ TEST_F(levin_notify, block_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -801,7 +869,7 @@ TEST_F(levin_notify, none_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -830,7 +898,7 @@ TEST_F(levin_notify, fluff_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -879,7 +947,7 @@ TEST_F(levin_notify, stem_with_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -921,6 +989,60 @@ TEST_F(levin_notify, stem_with_padding) } } +TEST_F(levin_notify, stem_no_outs_with_padding) +{ + cryptonote::levin::notify notifier = make_notifier(0, true, true); + + for (unsigned count = 0; count < 10; ++count) + add_connection(true); + + { + const auto status = notifier.get_status(); + EXPECT_FALSE(status.has_noise); + EXPECT_FALSE(status.connections_filled); + } + notifier.new_out_connection(); + io_service_.poll(); + + std::vector<cryptonote::blobdata> txs(2); + txs[0].resize(100, 'f'); + txs[1].resize(200, 'e'); + + std::vector<cryptonote::blobdata> sorted_txs = txs; + std::sort(sorted_txs.begin(), sorted_txs.end()); + + ASSERT_EQ(10u, contexts_.size()); + + auto context = contexts_.begin(); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); + + io_service_.reset(); + ASSERT_LT(0u, io_service_.poll()); + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff)); + if (events_.has_stem_txes()) + EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem)); + + notifier.run_fluff(); + ASSERT_LT(0u, io_service_.poll()); + + std::size_t send_count = 0; + EXPECT_EQ(0u, context->process_send_queue()); + for (++context; context != contexts_.end(); ++context) + { + send_count += context->process_send_queue(); + } + + EXPECT_EQ(9u, send_count); + ASSERT_EQ(9u, receiver_.notified_size()); + for (unsigned count = 0; count < 9u; ++count) + { + auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second; + EXPECT_EQ(sorted_txs, notification.txs); + EXPECT_FALSE(notification._.empty()); + EXPECT_TRUE(notification.dandelionpp_fluff); + } +} + TEST_F(levin_notify, local_with_padding) { cryptonote::levin::notify notifier = make_notifier(0, true, true); @@ -946,7 +1068,7 @@ TEST_F(levin_notify, local_with_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1013,7 +1135,7 @@ TEST_F(levin_notify, forward_with_padding) while (!has_stemmed || !has_fluffed) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1077,7 +1199,7 @@ TEST_F(levin_notify, block_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1106,7 +1228,7 @@ TEST_F(levin_notify, none_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1135,7 +1257,7 @@ TEST_F(levin_notify, private_fluff_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1186,7 +1308,7 @@ TEST_F(levin_notify, private_stem_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1237,7 +1359,7 @@ TEST_F(levin_notify, private_local_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1288,7 +1410,7 @@ TEST_F(levin_notify, private_forward_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1339,7 +1461,7 @@ TEST_F(levin_notify, private_block_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1369,7 +1491,7 @@ TEST_F(levin_notify, private_none_without_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1398,7 +1520,7 @@ TEST_F(levin_notify, private_fluff_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::fluff)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1448,7 +1570,7 @@ TEST_F(levin_notify, private_stem_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1498,7 +1620,7 @@ TEST_F(levin_notify, private_local_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1548,7 +1670,7 @@ TEST_F(levin_notify, private_forward_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::forward)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::forward)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1598,7 +1720,7 @@ TEST_F(levin_notify, private_block_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::block)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1627,7 +1749,7 @@ TEST_F(levin_notify, private_none_with_padding) ASSERT_EQ(10u, contexts_.size()); { auto context = contexts_.begin(); - EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none)); + EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::none)); io_service_.reset(); ASSERT_EQ(0u, io_service_.poll()); @@ -1659,7 +1781,7 @@ TEST_F(levin_notify, stem_mappings) for (;;) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1721,7 +1843,7 @@ TEST_F(levin_notify, stem_mappings) for (unsigned i = 0; i < contexts_.size() * 2; i += 2) { auto& incoming = contexts_[i % contexts_.size()]; - EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1782,7 +1904,7 @@ TEST_F(levin_notify, fluff_multiple) for (;;) { auto context = contexts_.begin(); - EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1841,7 +1963,7 @@ TEST_F(levin_notify, fluff_multiple) for (unsigned i = 0; i < contexts_.size() * 2; i += 2) { auto& incoming = contexts_[i % contexts_.size()]; - EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), cryptonote::relay_method::stem)); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1905,7 +2027,7 @@ TEST_F(levin_notify, noise) EXPECT_EQ(0u, receiver_.notified_size()); } - EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::local)); + EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::local)); notifier.run_stems(); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1927,7 +2049,7 @@ TEST_F(levin_notify, noise) } txs[0].resize(3000, 'r'); - EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::fluff)); + EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::fluff)); notifier.run_stems(); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); @@ -1996,7 +2118,7 @@ TEST_F(levin_notify, noise_stem) EXPECT_EQ(0u, receiver_.notified_size()); } - EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::stem)); + EXPECT_TRUE(notifier.send_txs(txs, incoming_id, cryptonote::relay_method::stem)); notifier.run_stems(); io_service_.reset(); ASSERT_LT(0u, io_service_.poll()); diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp index 588e91d02..0191e5aa4 100644 --- a/tests/unit_tests/node_server.cpp +++ b/tests/unit_tests/node_server.cpp @@ -47,9 +47,10 @@ namespace cryptonote { class test_core : public cryptonote::i_core_events { public: + virtual bool is_synchronized() const final { return true; } void on_synchronized(){} void safesyncmode(const bool){} - uint64_t get_current_blockchain_height() const {return 1;} + virtual uint64_t get_current_blockchain_height() const final {return 1;} void set_target_blockchain_height(uint64_t) {} bool init(const boost::program_options::variables_map& vm) {return true ;} bool deinit(){return true;} diff --git a/utils/systemd/monerod.service b/utils/systemd/monerod.service index dbb9e8aaa..c89e31f8c 100644 --- a/utils/systemd/monerod.service +++ b/utils/systemd/monerod.service @@ -6,16 +6,15 @@ After=network.target User=monero Group=monero WorkingDirectory=~ -RuntimeDirectory=monero StateDirectory=monero LogsDirectory=monero # Clearnet config # -Type=forking -PIDFile=/run/monero/monerod.pid -ExecStart=/usr/bin/monerod --config-file /etc/monerod.conf \ - --detach --pidfile /run/monero/monerod.pid +Type=simple +ExecStart=/usr/bin/monerod --config-file /etc/monerod.conf --non-interactive +StandardOutput=null +StandardError=null # Tor config # |