From 3aa1aa8a6168c8e1408692e669c9fffb51b9aad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 26 Jul 2023 12:28:22 +0500 Subject: [PATCH 01/62] build: CMake: Make ASM compiler optional --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f458556791..e9ea4d4d38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ project("Gridcoin" VERSION 5.4.5.4 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" - LANGUAGES ASM C CXX + LANGUAGES C CXX ) set(CLIENT_VERSION_IS_RELEASE "false") @@ -114,6 +114,10 @@ if(SYSTEM_UNIVALUE) pkg_check_modules(UNIVALUE REQUIRED IMPORTED_TARGET libunivalue) endif() +if(USE_ASM) + enable_language(ASM) +endif() + if(ENABLE_GUI) find_package(Qt5 ${QT5_MINIMUM_VERSION} REQUIRED COMPONENTS Concurrent From 5fd63fa824a08cc36dc2a31589fa3debbd80f4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 13:41:45 +0500 Subject: [PATCH 02/62] build: CMake: Support bundled Boost This starts a series of commits introducing Hunter Package Manager support. The end goal is to make building with CMake on Windows possible. --- CMakeLists.txt | 55 ++- build-aux/cmake/Hunter/config.cmake | 0 build-aux/cmake/HunterGate.cmake | 543 ++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 +- 4 files changed, 589 insertions(+), 11 deletions(-) create mode 100644 build-aux/cmake/Hunter/config.cmake create mode 100644 build-aux/cmake/HunterGate.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e9ea4d4d38..1eab634228 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,25 @@ # CMake support is experimental. Use with caution and report any bugs. cmake_minimum_required(VERSION 3.18) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build-aux/cmake") + + +# Hunter Package Manager +# ====================== + +# Windows doesn't yet have a package manager that can be used for managing +# dependencies, so we use Hunter on it. +option(HUNTER_ENABLED "Enable Hunter package manager" OFF) +include(HunterGate) +HunterGate( + URL "https://github.com/cpp-pm/hunter/archive/refs/tags/v0.25.3.tar.gz" + SHA1 "0dfbc2cb5c4cf7e83533733bdfd2125ff96680cb" + FILEPATH "${CMAKE_CURRENT_SOURCE_DIR}/build-aux/cmake/Hunter/config.cmake" +) + + +# Project configuration +# ===================== project("Gridcoin" VERSION 5.4.5.4 @@ -37,20 +56,21 @@ string(REPLACE "NDEBUG" "_NDEBUG" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_REL string(REPLACE "NDEBUG" "_NDEBUG" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") -# Load modules from the source tree -# ================================= - -set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build-aux/cmake") +# Load CMake modules +# ================== include(CheckCXXSymbolExists) include(CheckFunctionExists) include(CheckIncludeFile) include(CheckPIESupported) +include(CheckSymbolExists) + include(CheckSSE) include(CheckStrerrorR) -include(CheckSymbolExists) +include(HunterGate) include(VersionFromGit) + # Define options # ============== @@ -74,21 +94,32 @@ option(ENABLE_QRENCODE "Enable generation of QR Codes for receiving payments" O option(ENABLE_UPNP "Enable UPnP port mapping support" OFF) option(DEFAULT_UPNP "Turn UPnP on startup" OFF) option(USE_DBUS "Enable DBus support" OFF) + +# Bundled packages option(SYSTEM_BDB "Find system installation of Berkeley DB CXX 5.3" OFF) option(SYSTEM_LEVELDB "Find system installation of leveldb" OFF) option(SYSTEM_SECP256K1 "Find system installation of libsecp256k1 with pkg-config" OFF) option(SYSTEM_UNIVALUE "Find system installation of Univalue with pkg-config" OFF) option(SYSTEM_XXD "Find system xxd binary" OFF) +# Hunter packages +option(BUNDLED_BOOST "Use the bundled version of Boost" ${HUNTER_ENABLED}) -# Find dependencies -# ================= -set(BOOST_MINIMUM_VERSION 1.63.0) +# Handle dependencies +# =================== + set(QT5_MINIMUM_VERSION 5.15.0) +set(BOOST_MINIMUM_VERSION 1.63.0) +set(BOOST_COMPONENTS filesystem iostreams thread) +set(BOOST_HUNTER_COMPONENTS ${BOOST_COMPONENTS}) +if(ENABLE_TESTS) + list(APPEND BOOST_COMPONENTS unit_test_framework) + list(APPEND BOOST_HUNTER_COMPONENTS test) +endif() + find_package(Atomics REQUIRED) -find_package(Boost ${BOOST_MINIMUM_VERSION} COMPONENTS filesystem iostreams thread REQUIRED) find_package(CURL COMPONENTS HTTP HTTPS SSL REQUIRED) find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED) @@ -114,6 +145,11 @@ if(SYSTEM_UNIVALUE) pkg_check_modules(UNIVALUE REQUIRED IMPORTED_TARGET libunivalue) endif() +if(BUNDLED_BOOST) + hunter_add_package(Boost COMPONENTS ${BOOST_HUNTER_COMPONENTS}) +endif() +find_package(Boost ${BOOST_MINIMUM_VERSION} COMPONENTS ${BOOST_COMPONENTS} CONFIG REQUIRED) + if(USE_ASM) enable_language(ASM) endif() @@ -146,7 +182,6 @@ if(ENABLE_UPNP) endif() if(ENABLE_TESTS) - find_package(Boost ${BOOST_MINIMUM_VERSION} COMPONENTS unit_test_framework REQUIRED) enable_testing() if(SYSTEM_XXD) diff --git a/build-aux/cmake/Hunter/config.cmake b/build-aux/cmake/Hunter/config.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/build-aux/cmake/HunterGate.cmake b/build-aux/cmake/HunterGate.cmake new file mode 100644 index 0000000000..17c6d38038 --- /dev/null +++ b/build-aux/cmake/HunterGate.cmake @@ -0,0 +1,543 @@ +# Copyright (c) 2013-2019, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 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. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.5) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/cpp-pm/gate/ +# * https://github.com/cpp-pm/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) + +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.5") + message( + FATAL_ERROR + "At least CMake version 3.5 required for Hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF." + ) + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) +set(HUNTER_ROOT "" CACHE FILEPATH "Override the HUNTER_ROOT.") + +set(HUNTER_ERROR_PAGE "https://hunter.readthedocs.io/en/latest/reference/errors") + +function(hunter_gate_status_print) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + message(STATUS "[hunter] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_status_debug) + if(HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_error_page error_page) + message("------------------------------ ERROR ------------------------------") + message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") + if("${hunter_ERROR_PAGE}" STREQUAL "") + hunter_gate_internal_error("Expected ERROR_PAGE") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("${hunter_ERROR_PAGE}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + if(HUNTER_ROOT) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + if(DEFINED ENV{HUNTER_ROOT}) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + if(DEFINED ENV{HOME}) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + if(DEFINED ENV{SYSTEMDRIVE}) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + if(DEFINED ENV{USERPROFILE}) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + ERROR_PAGE "error.detect.hunter.root" + ) +endfunction() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + ERROR_PAGE "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.5)\n" + "if(POLICY CMP0114)\n" + " cmake_policy(SET CMP0114 NEW)\n" + "endif()\n" + "if(POLICY CMP0135)\n" + " cmake_policy(SET CMP0135 NEW)\n" + "endif()\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error( + "Configure project failed." + "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" + "In directory ${dir}" + ) + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + ERROR_PAGE "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + ERROR_PAGE "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(TOLOWER "${_sha1_value}" _sha1_value_lower) + string(TOLOWER "${HUNTER_GATE_SHA1}" _HUNTER_GATE_SHA1_lower) + string(COMPARE EQUAL "${_sha1_value_lower}" "${_HUNTER_GATE_SHA1_lower}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 012281546c..02dc647772 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -220,7 +220,7 @@ target_include_directories(gridcoin_util PUBLIC target_link_libraries(gridcoin_util PUBLIC -lm ${ATOMICS_LIBRARIES} ${RT_LIBRARIES} ${LIBBDB_CXX} ${LIBLEVELDB} ${LIBSECP256K1} ${LIBUNIVALUE} - Boost::filesystem Boost::headers Boost::iostreams Boost::thread + Boost::boost Boost::filesystem Boost::iostreams Boost::thread CURL::libcurl OpenSSL::Crypto OpenSSL::SSL Threads::Threads From 1e9b371313dc6da57b559c971fddbe44edc286f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 14:17:40 +0500 Subject: [PATCH 03/62] build: CMake: Support bundled OpenSSL --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eab634228..640ca7734c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ option(SYSTEM_XXD "Find system xxd binary" OFF) # Hunter packages option(BUNDLED_BOOST "Use the bundled version of Boost" ${HUNTER_ENABLED}) +option(BUNDLED_OPENSSL "Use the bundled version of OpenSSL" ${HUNTER_ENABLED}) # Handle dependencies @@ -121,7 +122,6 @@ endif() find_package(Atomics REQUIRED) find_package(CURL COMPONENTS HTTP HTTPS SSL REQUIRED) -find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED) find_package(libzip REQUIRED) @@ -150,6 +150,11 @@ if(BUNDLED_BOOST) endif() find_package(Boost ${BOOST_MINIMUM_VERSION} COMPONENTS ${BOOST_COMPONENTS} CONFIG REQUIRED) +if(BUNDLED_OPENSSL) + hunter_add_package(OpenSSL) +endif() +find_package(OpenSSL REQUIRED) + if(USE_ASM) enable_language(ASM) endif() From d43cc504b16f786c139d89968c86c0ac8799e761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 14:17:58 +0500 Subject: [PATCH 04/62] build: CMake: Support bundled cURL --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 640ca7734c..7256ed5aeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ option(SYSTEM_XXD "Find system xxd binary" OFF) # Hunter packages option(BUNDLED_BOOST "Use the bundled version of Boost" ${HUNTER_ENABLED}) +option(BUNDLED_CURL "Use the bundled version of cURL" ${HUNTER_ENABLED}) option(BUNDLED_OPENSSL "Use the bundled version of OpenSSL" ${HUNTER_ENABLED}) @@ -121,7 +122,6 @@ if(ENABLE_TESTS) endif() find_package(Atomics REQUIRED) -find_package(CURL COMPONENTS HTTP HTTPS SSL REQUIRED) find_package(Threads REQUIRED) find_package(libzip REQUIRED) @@ -155,6 +155,13 @@ if(BUNDLED_OPENSSL) endif() find_package(OpenSSL REQUIRED) +if(BUNDLED_CURL) + hunter_add_package(CURL) + find_package(CURL CONFIG REQUIRED) +else() + find_package(CURL REQUIRED) +endif() + if(USE_ASM) enable_language(ASM) endif() From 5456a0d97c567a46124babb93a5327888f9f2abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 14:31:52 +0500 Subject: [PATCH 05/62] build: CMake: Support bundled libzip --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7256ed5aeb..095484f2c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,7 @@ option(SYSTEM_XXD "Find system xxd binary" OFF) # Hunter packages option(BUNDLED_BOOST "Use the bundled version of Boost" ${HUNTER_ENABLED}) option(BUNDLED_CURL "Use the bundled version of cURL" ${HUNTER_ENABLED}) +option(BUNDLED_LIBZIP "Use the bundled version of libzip" ${HUNTER_ENABLED}) option(BUNDLED_OPENSSL "Use the bundled version of OpenSSL" ${HUNTER_ENABLED}) @@ -123,7 +124,6 @@ endif() find_package(Atomics REQUIRED) find_package(Threads REQUIRED) -find_package(libzip REQUIRED) if(SYSTEM_BDB) find_package(BerkeleyDB 5.3...<5.4 COMPONENTS CXX REQUIRED) @@ -162,6 +162,11 @@ else() find_package(CURL REQUIRED) endif() +if(BUNDLED_LIBZIP) + hunter_add_package(libzip) +endif() +find_package(libzip CONFIG REQUIRED) + if(USE_ASM) enable_language(ASM) endif() From 33c0bdb2e42920cdf63570aeba90497ab9f5afc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 15:31:04 +0500 Subject: [PATCH 06/62] build: CMake: Support bundled Qt --- CMakeLists.txt | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 095484f2c1..e7f9408625 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,12 +107,21 @@ option(BUNDLED_BOOST "Use the bundled version of Boost" ${HUNTER_ENABLED}) option(BUNDLED_CURL "Use the bundled version of cURL" ${HUNTER_ENABLED}) option(BUNDLED_LIBZIP "Use the bundled version of libzip" ${HUNTER_ENABLED}) option(BUNDLED_OPENSSL "Use the bundled version of OpenSSL" ${HUNTER_ENABLED}) +option(BUNDLED_QT "Use the bundled version of Qt" ${HUNTER_ENABLED}) # Handle dependencies # =================== -set(QT5_MINIMUM_VERSION 5.15.0) +set(QT5_MINIMUM_VERSION 5.9.5) +set(QT5_COMPONENTS Concurrent Core Gui LinguistTools Network Widgets) +set(QT5_HUNTER_COMPONENTS qtbase qttools) +if(USE_DBUS) + list(APPEND QT5_COMPONENTS DBus) +endif() +if(ENABLE_TESTS) + list(APPEND QT5_COMPONENTS Test) +endif() set(BOOST_MINIMUM_VERSION 1.63.0) set(BOOST_COMPONENTS filesystem iostreams thread) @@ -172,26 +181,25 @@ if(USE_ASM) endif() if(ENABLE_GUI) - find_package(Qt5 ${QT5_MINIMUM_VERSION} REQUIRED COMPONENTS - Concurrent - Core - Gui - LinguistTools - Network - Widgets - ) - - if(USE_DBUS) - find_package(Qt5 ${QT5_MINIMUM_VERSION} COMPONENTS DBus REQUIRED) - endif() - - if(ENABLE_TESTS) - find_package(Qt5 ${QT5_MINIMUM_VERSION} COMPONENTS Test REQUIRED) + if(BUNDLED_QT) + hunter_add_package(Qt COMPONENTS ${QT5_HUNTER_COMPONENTS}) endif() + find_package(Qt5 ${QT5_MINIMUM_VERSION} COMPONENTS ${QT5_COMPONENTS} REQUIRED) if(ENABLE_QRENCODE) pkg_check_modules(QRENCODE REQUIRED IMPORTED_TARGET libqrencode) endif() + + # Compatibility macros + if(Qt5Core_VERSION VERSION_LESS 5.15.0) + macro(qt_create_translation) + qt5_create_translation(${ARGN}) + endmacro() + + macro(qt_add_translation) + qt5_add_translation(${ARGN}) + endmacro() + endif() endif() if(ENABLE_UPNP) From 01437cb4cd8166d7357e9253f223ef34bcfa4971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 17:30:55 +0500 Subject: [PATCH 07/62] build: CMake: Don't assume that ./configure can be executed --- CMakeLists.txt | 3 ++- src/bdb53/CMakeLists.txt | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f9408625..3eb6ef52d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,8 @@ find_package(Threads REQUIRED) if(SYSTEM_BDB) find_package(BerkeleyDB 5.3...<5.4 COMPONENTS CXX REQUIRED) else() - find_program(MAKE_EXE NAMES gmake nmake make) + find_program(SH_EXE NAMES sh bash REQUIRED) + find_program(MAKE_EXE NAMES gmake nmake make REQUIRED) endif() if(SYSTEM_LEVELDB) diff --git a/src/bdb53/CMakeLists.txt b/src/bdb53/CMakeLists.txt index 1c98273b73..5af5c845c7 100644 --- a/src/bdb53/CMakeLists.txt +++ b/src/bdb53/CMakeLists.txt @@ -1,7 +1,14 @@ include(ExternalProject) +set(LIBDB_DIST_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dist") +set(LIBDB_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/libdb_build") +set(libdb_cxx_library "${LIBDB_BUILD_DIR}/libdb_cxx.a") +set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1) + + # Configure flags # =============== + set(BDB_FLAGS --disable-java --disable-jdbc @@ -13,9 +20,13 @@ if(ENABLE_PIE) --with-pic ) endif() -if(MINGW) +if(WIN32) + # configure script doesn't support DOS-style paths + cmake_path(SET relative_dist_dir "${LIBDB_DIST_DIR}") + cmake_path(RELATIVE_PATH relative_dist_dir BASE_DIRECTORY "${LIBDB_BUILD_DIR}") list(APPEND BDB_FLAGS --enable-mingw + --srcdir "${relative_dist_dir}" ) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -40,14 +51,10 @@ set(MAKEOPTS "-j${N}" CACHE STRING "Options for the 'make' program") # External project # ================ -set(LIBDB_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/libdb_build) -set(libdb_cxx_library ${LIBDB_BUILD_DIR}/libdb_cxx.a) -set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1) - ExternalProject_Add(BerkeleyDB_Project SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} BINARY_DIR ${LIBDB_BUILD_DIR} - CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/dist/configure ${BDB_FLAGS} + CONFIGURE_COMMAND ${SH_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/dist/configure ${BDB_FLAGS} BUILD_COMMAND COMMAND ${MAKE_EXE} ${MAKEOPTS} clean COMMAND ${MAKE_EXE} ${MAKEOPTS} libdb_cxx.a From 9ceab0145ac2dbcbe03c90eca9a4956d6baf907b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Thu, 30 Nov 2023 00:26:40 +0500 Subject: [PATCH 08/62] build: CMake: Ban MSVC compiler There are lots of build failures using it. Pulling newer Bitcoin code should help. --- CMakeLists.txt | 15 ++++++++++----- src/crypto/CMakeLists.txt | 12 +++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eb6ef52d0..75a021b8f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,17 +43,22 @@ set(COPYRIGHT_HOLDERS_FINAL "The Gridcoin developers") # ======================= set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden) -set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) - set(CMAKE_INCLUDE_CURRENT_DIR ON) -# Remove '-DNDEBUG' from flags because we need asserts -string(REPLACE "NDEBUG" "_NDEBUG" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") -string(REPLACE "NDEBUG" "_NDEBUG" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +if(MSVC) + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + message(FATAL_ERROR "It's not yet possible to build Gridcoin with MSVC") + endif() + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) + add_compile_options(/U NDEBUG) +else() + add_compile_options(-UNDEBUG) +endif() # Load CMake modules diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index f7972902be..7f9811e744 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -22,21 +22,27 @@ if(ENABLE_SSE41) list(APPEND LIBGRIDCOIN_CRYPTO gridcoin_crypto_sse41) add_library(gridcoin_crypto_sse41 STATIC sha256_sse41.cpp) target_compile_definitions(gridcoin_crypto_sse41 PRIVATE ENABLE_SSE41) - target_compile_options(gridcoin_crypto_sse41 PRIVATE -msse4.1) + if(NOT MSVC) + target_compile_options(gridcoin_crypto_sse41 PRIVATE -msse4.1) + endif() endif() if(ENABLE_AVX2) list(APPEND LIBGRIDCOIN_CRYPTO gridcoin_crypto_avx2) add_library(gridcoin_crypto_avx2 STATIC sha256_avx2.cpp) target_compile_definitions(gridcoin_crypto_avx2 PRIVATE ENABLE_AVX2) - target_compile_options(gridcoin_crypto_avx2 PRIVATE -mavx -mavx2) + if(NOT MSVC) + target_compile_options(gridcoin_crypto_avx2 PRIVATE -mavx -mavx2) + endif() endif() if(ENABLE_X86_SHANI) list(APPEND LIBGRIDCOIN_CRYPTO gridcoin_crypto_x86_shani) add_library(gridcoin_crypto_x86_shani STATIC sha256_x86_shani.cpp) target_compile_definitions(gridcoin_crypto_x86_shani PRIVATE ENABLE_X86_SHANI) - target_compile_options(gridcoin_crypto_x86_shani PRIVATE -msse4 -msha) + if(NOT MSVC) + target_compile_options(gridcoin_crypto_x86_shani PRIVATE -msse4 -msha) + endif() endif() if(ENABLE_ARM_SHANI) From 6c57ebe942a4434ae82c4bb436d608210d17e9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sun, 3 Dec 2023 16:20:02 +0500 Subject: [PATCH 09/62] build: CMake: Fix build of *.rc files --- src/CMakeLists.txt | 3 +++ src/qt/CMakeLists.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02dc647772..e949598fac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -257,6 +257,9 @@ if(ENABLE_DAEMON) if(WIN32) target_sources(gridcoinresearchd PRIVATE gridcoinresearchd-res.rc) + set_source_files_properties(gridcoinresearchd-res.rc PROPERTIES + COMPILE_DEFINITIONS WINDRES_PREPROC + ) endif() if(UNIX AND NOT APPLE) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 3302a30599..c47c1fa13f 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -99,6 +99,9 @@ add_library(gridcoinqt STATIC if(WIN32) target_sources(gridcoinqt PRIVATE res/gridcoinresearch.rc) + set_source_files_properties(res/gridcoinresearch.rc PROPERTIES + COMPILE_DEFINITIONS WINDRES_PREPROC + ) elseif(APPLE) target_sources(gridcoinqt PRIVATE macdockiconhandler.mm From 3886784aa9a3043861b1ccbf46010014ed04b468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sun, 3 Dec 2023 16:38:15 +0500 Subject: [PATCH 10/62] build: CMake: Link with Ws2_32 on Windows --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e949598fac..55a61b1415 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -228,6 +228,10 @@ target_link_libraries(gridcoin_util PUBLIC ) target_link_libraries(gridcoin_util PUBLIC ${LIBGRIDCOIN_CRYPTO}) +if(WIN32) + target_link_libraries(gridcoin_util PUBLIC wsock32 Ws2_32) +endif() + target_compile_definitions(gridcoin_util PUBLIC HAVE_CONFIG_H HAVE_BUILD_INFO From 5b36ce32bdaf489b5afb4578477df0a7bbbc7885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sat, 27 Jan 2024 04:58:29 +0500 Subject: [PATCH 11/62] build: CMake: Use static secp256k1 (if bundled) --- src/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55a61b1415..cc1778d82c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,10 +78,10 @@ else() endif() add_subdirectory(secp256k1 EXCLUDE_FROM_ALL) - target_include_directories(secp256k1 PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}/secp256k1/include" + target_include_directories(secp256k1_static PUBLIC + $ ) - set(LIBSECP256K1 secp256k1) + set(LIBSECP256K1 secp256k1_static) endif() if(SYSTEM_UNIVALUE) From b6174350ab9c9c8ed21cf7fb812e1e01a36f2c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sat, 27 Jan 2024 05:18:03 +0500 Subject: [PATCH 12/62] build: CMake: Add option for static runtime Enabled by default on Windows. --- CMakeLists.txt | 12 ++++++++++-- src/CMakeLists.txt | 2 +- src/qt/CMakeLists.txt | 1 + src/qt/test/CMakeLists.txt | 1 + src/test/CMakeLists.txt | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75a021b8f0..8c8ba57859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,6 @@ if(MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message(FATAL_ERROR "It's not yet possible to build Gridcoin with MSVC") endif() - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) add_compile_options(/U NDEBUG) else() add_compile_options(-UNDEBUG) @@ -85,6 +84,7 @@ option(ENABLE_GUI "Enable Qt-based GUI" OFF) option(ENABLE_DOCS "Build Doxygen documentation" OFF) option(ENABLE_TESTS "Build tests" OFF) option(LUPDATE "Update translation files" OFF) +option(STATIC_RUNTIME "Link runtime statically" ${WIN32}) # CPU-dependent options option(ENABLE_SSE41 "Build code that uses SSE4.1 intrinsics" ${HAS_SSE41}) @@ -245,12 +245,20 @@ endif() set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIE}) # Set compiler flags -if (APPLE) +if(APPLE) add_compile_options(-Wno-error=deprecated-declarations) add_compile_options(-Wno-error=thread-safety-analysis) add_compile_options(-Wno-error=thread-safety-reference) endif() +if(STATIC_RUNTIME) + if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)\$") + list(APPEND RUNTIME_LIBS -static-libgcc -static-libstdc++) + elseif(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() +endif() + # Set endianness if(CMAKE_CXX_BYTE_ORDER EQUAL BIG_ENDIAN) set(WORDS_BIGENDIAN 1) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc1778d82c..d13071850e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -257,7 +257,7 @@ endif() if(ENABLE_DAEMON) add_executable(gridcoinresearchd gridcoinresearchd.cpp) - target_link_libraries(gridcoinresearchd PUBLIC gridcoin_util) + target_link_libraries(gridcoinresearchd PUBLIC ${RUNTIME_LIBS} gridcoin_util) if(WIN32) target_sources(gridcoinresearchd PRIVATE gridcoinresearchd-res.rc) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index c47c1fa13f..14a7e45b77 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -176,6 +176,7 @@ add_dependencies(gridcoinqt gridcoinqt_l10n) add_executable(gridcoinresearch WIN32 MACOSX_BUNDLE bitcoin.cpp) target_link_libraries(gridcoinresearch PRIVATE + ${RUNTIME_LIBS} Qt5::Widgets gridcoin_util gridcoinqt diff --git a/src/qt/test/CMakeLists.txt b/src/qt/test/CMakeLists.txt index 4717e74597..f6ff90608d 100644 --- a/src/qt/test/CMakeLists.txt +++ b/src/qt/test/CMakeLists.txt @@ -8,6 +8,7 @@ set_target_properties(test_gridcoin-qt PROPERTIES ) target_link_libraries(test_gridcoin-qt PRIVATE + ${RUNTIME_LIBS} Qt5::Test Qt5::Widgets gridcoin_util diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 7bed59e789..1555b347ec 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -56,6 +56,7 @@ add_executable(test_gridcoin add_subdirectory(data) target_link_libraries(test_gridcoin PRIVATE + ${RUNTIME_LIBS} Boost::unit_test_framework gridcoin_util ) From 1376180b6acd2964cc60e12ac5080728de4499c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sat, 27 Jan 2024 05:26:24 +0500 Subject: [PATCH 13/62] build: CMake: Add option to prefer static libs Enabled by default on Windows. --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c8ba57859..7d0b606562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ option(ENABLE_GUI "Enable Qt-based GUI" OFF) option(ENABLE_DOCS "Build Doxygen documentation" OFF) option(ENABLE_TESTS "Build tests" OFF) option(LUPDATE "Update translation files" OFF) +option(STATIC_LIBS "Prefer static variants of system libraries" ${WIN32}) option(STATIC_RUNTIME "Link runtime statically" ${WIN32}) # CPU-dependent options @@ -251,6 +252,11 @@ if(APPLE) add_compile_options(-Wno-error=thread-safety-reference) endif() +if(STATIC_LIBS) + set(CMAKE_LINK_SEARCH_START_STATIC ON) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_STATIC_LIBRARY_SUFFIX}") +endif() + if(STATIC_RUNTIME) if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)\$") list(APPEND RUNTIME_LIBS -static-libgcc -static-libstdc++) From 407e9f28fd52a9fd48b055c7094f195c22a78a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sat, 27 Jan 2024 06:17:31 +0500 Subject: [PATCH 14/62] build: CMake: Link with shlwapi on Windows --- src/qt/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 14a7e45b77..efeca4de5e 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -151,6 +151,8 @@ if(APPLE) "-framework ApplicationServices" "-framework AppKit" ) +elseif(WIN32) + target_link_libraries(gridcoinqt PUBLIC shlwapi) endif() target_compile_definitions(gridcoinqt PUBLIC HAVE_CONFIG_H) From e9f0dabbdc353989300dcc078e86686fd1ceaeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Wed, 29 Nov 2023 15:37:48 +0500 Subject: [PATCH 15/62] ci: Add CMake CI for MSYS2 --- .github/workflows/cmake-ci.yml | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/.github/workflows/cmake-ci.yml b/.github/workflows/cmake-ci.yml index dd34e2d624..2aa5545a7e 100644 --- a/.github/workflows/cmake-ci.yml +++ b/.github/workflows/cmake-ci.yml @@ -192,3 +192,87 @@ jobs: name: testlog-macos-${{matrix.tag}} path: ${{github.workspace}}/build/Testing/Temporary/LastTest.log retention-days: 7 + + test-msys2: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + env: + CCACHE_DIR: ${{github.workspace}}\ccache + CCACHE_MAXSIZE: 400M + CCACHE_COMPILERCHECK: content + strategy: + matrix: + tag: + - minimal + - no-asm + - gui-full + include: + - tag: no-asm + deps: null + options: -DUSE_ASM=OFF + - tag: gui-full + deps: >- + miniupnpc:p + qrencode:p + qt5-base:p + qt5-tools:p + options: >- + -DENABLE_GUI=ON + -DENABLE_QRENCODE=ON + -DENABLE_UPNP=ON + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: >- + make + ninja + pacboy: >- + ${{matrix.deps}} + boost:p + ccache:p + cmake:p + curl:p + libzip:p + openssl:p + toolchain:p + - name: Configure + run: | + cmake -B ./build -G Ninja \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + ${{matrix.options}} \ + -DBUILD_SHARED_LIBS=OFF -DENABLE_TESTS=ON + - name: Restore cache + uses: actions/cache/restore@v3 + if: always() + with: + path: ${{env.CCACHE_DIR}} + key: ccache-msys2-${{matrix.tag}}-${{github.run_id}} + restore-keys: | + ccache-msys2-${{matrix.tag}}- + - name: Build + run: | + cmake --build ./build -v -j $NUMBER_OF_PROCESSORS + - name: Save cache + uses: actions/cache/save@v3 + if: always() + with: + path: ${{env.CCACHE_DIR}} + key: ccache-msys2-${{matrix.tag}}-${{github.run_id}} + - name: Run tests + run: | + ctest --test-dir ./build -j $NUMBER_OF_PROCESSORS + - name: Upload test logs + uses: actions/upload-artifact@v3 + if: always() + with: + name: testlog-msys-${{matrix.tag}} + path: ${{github.workspace}}\build\Testing\Temporary\LastTest.log + retention-days: 7 From 4856ee18ac6fa5523153a00f8dd36736d705c3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sat, 27 Jan 2024 06:52:34 +0500 Subject: [PATCH 16/62] doc: Add MSYS2 build notes --- doc/README.md | 1 + doc/build-msys2.md | 53 ++++++++++++++++++++++++++++++++++++++++++++ doc/build-windows.md | 3 ++- doc/cmake-options.md | 4 ++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 doc/build-msys2.md diff --git a/doc/README.md b/doc/README.md index eaa6ad72bd..f6eab9e075 100644 --- a/doc/README.md +++ b/doc/README.md @@ -27,6 +27,7 @@ The following are developer notes on how to build Gridcoin on your native platfo - [OS X Build Notes](build-macos.md) - [Unix Build Notes](build-unix.md) - [Windows Build Notes](build-windows.md) +- [Windows (MSYS2) Build Notes](build-msys2.md) - [FreeBSD Build Notes](build-freebsd.md) - [OpenBSD Build Notes](build-openbsd.md) diff --git a/doc/build-msys2.md b/doc/build-msys2.md new file mode 100644 index 0000000000..d4c885a233 --- /dev/null +++ b/doc/build-msys2.md @@ -0,0 +1,53 @@ +Windows (MSYS2) Build Notes +=========================== + +This guide describes how to build gridcoinresearchd, command-line utilities, and GUI on Windows. + +Preparing the Build +------------------- + +First, install [MSYS2](https://www.msys2.org/). All commands below are supposed to be run in the **MSYS2 UCRT64** shell. + +Run the following to install the base dependencies for building: + +```bash +pacman -S make ninja pactoys +pacboy -S boost:p cmake:p curl:p libzip:p openssl:p toolchain:p +pacboy -S qrencode:p qt5-base:p qt5-tools:p # optional for the GUI +``` + +To Build +-------- + +### 1. Configuration + +To configure with gridcoinresearchd: + +```bash +mkdir build && cd build +cmake .. -DBUILD_SHARED_LIBS=OFF +``` + +To configure with GUI: + +```bash +mkdir build && cd build +cmake .. -DENABLE_GUI=ON -DBUILD_SHARED_LIBS=OFF +``` + +> [!NOTE] +> See also: [CMake Build Options](cmake-options.md) + +### 2. Compile + +```bash +cmake --build . # use "-j N" here for N parallel jobs +``` + +### 3. Test + +```bash +cmake .. -DENABLE_TESTS=ON +cmake --build . +ctest . +``` diff --git a/doc/build-windows.md b/doc/build-windows.md index 5f58bf1603..06e13b6943 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -1,7 +1,8 @@ WINDOWS BUILD NOTES ==================== -> This document is outdated. +> [!NOTE] +> See also: [Windows (MSYS2) Build Notes](build-msys2.md) Below are some notes on how to build Gridcoin for Windows. diff --git a/doc/cmake-options.md b/doc/cmake-options.md index 95cd8c4163..b38031aad7 100644 --- a/doc/cmake-options.md +++ b/doc/cmake-options.md @@ -23,6 +23,10 @@ ccmake . `cmake .. -DENABLE_PIE=ON -DUSE_ASM=OFF` +* Build a static binary: + + `cmake .. -DSTATIC_LIBS=ON -DSTATIC_RUNTIME=ON` + * Build tests and docs, run `lupdate`: `cmake .. -DENABLE_DOCS=ON -DENABLE_TESTS=ON -DLUPDATE=ON` From 6c4598a3ce4aadb13e520298e512cc97709fff51 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sat, 2 Mar 2024 21:14:01 -0500 Subject: [PATCH 17/62] Increment version to 5.4.6.1 for development --- CMakeLists.txt | 4 ++-- configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09cc834388..c5d2b8b1dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,13 +9,13 @@ cmake_minimum_required(VERSION 3.18) project("Gridcoin" - VERSION 5.4.6.0 + VERSION 5.4.6.1 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" LANGUAGES ASM C CXX ) -set(CLIENT_VERSION_IS_RELEASE "true") +set(CLIENT_VERSION_IS_RELEASE "false") set(COPYRIGHT_YEAR "2024") set(COPYRIGHT_HOLDERS_FINAL "The Gridcoin developers") diff --git a/configure.ac b/configure.ac index db4d895adc..8fa47af3b0 100755 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 0) -define(_CLIENT_VERSION_IS_RELEASE, true) +define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_IS_RELEASE, false) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Gridcoin]]) From 69710af200a0254262c92ddfb96f8bbf4fb6636d Mon Sep 17 00:00:00 2001 From: div72 Date: Sat, 2 Mar 2024 12:14:54 +0300 Subject: [PATCH 18/62] build: enforce SSE2 on x86 targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit targets the floating point errors caused by x87 floating point calculations breaking floating point equality on the testing suite. Let's take the disassembly from `project.m_rac == 123.45` check at src/test/gridcoin/researcher_tests.cpp#L272 for example: ``` │ 0x5911c7c5 fldl -0xa4(%ebp) ... │ 0x5911c7e0 fldt -0x6fa844(%esi) ... │ 0x5911c81d fucompp │ 0x5911c81f fnstsw %ax ``` The fldl instruction loads a double to the floating point registers, while the fldt instruction loads a long double(80-bits) to registers. Combining that with the fact that since ASLR is enabled, the one with the massive offset against the stack is probably the 123.45 float literal while the first instruction is for the project.m_rac. Before the fucompp instruction(which compares two floating points), the floating point registers look like this: ``` st0 123.449999999999999997 (raw 0x4005f6e6666666666666) st1 123.450000000000002842 (raw 0x4005f6e6666666666800) ``` The x87 floating point registers seem to work like a stack, since the first fldl instruction loads the 123.450...2842 and the second fldt instruction loads the 123.449...97 value. From the raw value, it seems the first 8 bytes of the values are identical, but the last two bytes (corresponding to the extra 16 bits granted by the x87 extension, which should map to the fraction part of the float) differ slightly, which seems to cause the fucompp instruction to think that these two values are different. This is normally not a problem, as floating point equality comparisons are expected to be not stable. The problem however arises from the fact that it is the **literal 123.45** whose value is off. When a basic C program is compiled(with -m32 option or in a 32-bit environment), the loaded value for 123.45 is identical to the computed value in the st1 register; which means something is going wrong in either during runtime loading of the value or compile-time storing of the value. GDB is unable to actually read that memory address weirdly, so I'm unable to exactly pinpoint which. Because of the issue lying on the extra bits of the fp register, I assumed that the -ffloat-store(which should've ensured registers to not have more precision than a double) or the -fexcess-precision=standard(an option which should be a superset of the former) or the -mpc64(an option which rounds the significand of the results of FP ops to 53-bits) should have fixed the issue, but they didn't and I will not bother to re-examine the disassembly to figure out why. Rather than that, this commit enforces the SSE2 instructions for the FP operations, which are already used on x86_64 hosts and operate under double precision instead of long double. This should be fine compatibility wise, as SSE2 is supported on CPUs after Pentium 4 where I assume the prior CPUs don't have enough computing power to run the client in the first place. --- configure.ac | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/configure.ac b/configure.ac index 8fa47af3b0..d0b56fb0e3 100755 --- a/configure.ac +++ b/configure.ac @@ -278,6 +278,16 @@ if test "$CXXFLAGS_overridden" = "no"; then AX_CHECK_COMPILE_FLAG([-Wdeprecated-copy],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-copy"],,[[$CXXFLAG_WERROR]]) fi + +dnl x87 FP operations on x86 hosts can break assumptions made about the floating point values. +dnl See the commit message which introduced this change for more details. +case $host in + i?86-*|x86_64-*) + AX_CHECK_COMPILE_FLAG([-msse2],[CXXFLAGS="$CXXFLAGS -msse2 -mfpmath=sse"],[AC_MSG_ERROR([SSE2 support is required on x86 targets.])],[[$CXXFLAG_WERROR]]) + ;; + *) ;; +esac + enable_sse42=no enable_sse41=no enable_avx2=no From 6bc0c711a27b951b845581ce882e2c92cd227fbc Mon Sep 17 00:00:00 2001 From: div72 Date: Sat, 2 Mar 2024 12:15:20 +0300 Subject: [PATCH 19/62] Revert "Implement comp_double comparison function in certain tests" This reverts commit 7bfd1b4a094c4211a84b00d3aff76f7bb9c50db2. --- src/test/gridcoin/claim_tests.cpp | 34 +++---------- src/test/gridcoin/researcher_tests.cpp | 68 +++++++++----------------- 2 files changed, 31 insertions(+), 71 deletions(-) diff --git a/src/test/gridcoin/claim_tests.cpp b/src/test/gridcoin/claim_tests.cpp index 33d1e204ad..0a9b5f1af4 100644 --- a/src/test/gridcoin/claim_tests.cpp +++ b/src/test/gridcoin/claim_tests.cpp @@ -97,26 +97,6 @@ static CKey GetTestPrivateKey() return key; } - -// Unfortunately, GCC 13 on openSUSE i386 is misbehaving and exhibiting weird errors in the last decimal places for things -// even as straightforward as -// -// double foo = 0.0; -// text >> foo. -// -// This comparison function works around that by allowing a small error band to pass the tests, but not enough to invalidate -// the tests on compilers that work. -bool comp_double(double lhs, double rhs) -{ - // Require exact match if 0=0. - if (std::min(lhs, rhs) == 0.0) { - return (lhs == rhs); - } else { - double unsigned_rel_error = std::abs(lhs - rhs) / std::min(lhs, rhs); - - return (unsigned_rel_error <= double {1e-8}); - } -} } // anonymous namespace // ----------------------------------------------------------------------------- @@ -138,7 +118,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_to_an_empty_claim) BOOST_CHECK(claim.m_magnitude == 0); BOOST_CHECK(claim.m_research_subsidy == 0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature.empty() == true); @@ -161,7 +141,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_to_the_specified_version) BOOST_CHECK(claim.m_magnitude == 0); BOOST_CHECK(claim.m_research_subsidy == 0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature.empty() == true); @@ -240,7 +220,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_legacy_boincblock_string_for_researcher) BOOST_CHECK(claim.m_magnitude == 123); BOOST_CHECK(claim.m_research_subsidy == 47.25 * COIN); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.123456)); + BOOST_CHECK(claim.m_magnitude_unit == 0.123456); BOOST_CHECK(claim.m_signature == signature); @@ -523,7 +503,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_investor) BOOST_CHECK(claim.m_research_subsidy == 0); BOOST_CHECK(claim.m_magnitude == 0.0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature.empty() == true); BOOST_CHECK(claim.m_quorum_address.empty() == true); BOOST_CHECK(claim.m_superblock->WellFormed() == false); @@ -565,7 +545,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_investor_with_superblock) BOOST_CHECK(claim.m_research_subsidy == 0); BOOST_CHECK(claim.m_magnitude == 0.0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature.empty() == true); } @@ -650,7 +630,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_researcher) BOOST_CHECK(claim.m_research_subsidy == expected.m_research_subsidy); BOOST_CHECK(claim.m_magnitude == 0.0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature == expected.m_signature); BOOST_CHECK(claim.m_quorum_hash == expected.m_quorum_hash); @@ -690,7 +670,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream_for_researcher_with_superbloc BOOST_CHECK(claim.m_research_subsidy == expected.m_research_subsidy); BOOST_CHECK(claim.m_magnitude == 0.0); - BOOST_CHECK(comp_double(claim.m_magnitude_unit, 0.0)); + BOOST_CHECK(claim.m_magnitude_unit == 0.0); BOOST_CHECK(claim.m_signature == expected.m_signature); BOOST_CHECK(claim.m_quorum_hash == expected.m_quorum_hash); diff --git a/src/test/gridcoin/researcher_tests.cpp b/src/test/gridcoin/researcher_tests.cpp index e163fb5862..352c2b464f 100644 --- a/src/test/gridcoin/researcher_tests.cpp +++ b/src/test/gridcoin/researcher_tests.cpp @@ -183,26 +183,6 @@ void AddProtocolEntry(const uint32_t& payload_version, const std::string& key, c registry.Add({contract, dummy_tx, &dummy_index}); } - -// Unfortunately, GCC 13 on openSUSE i386 is misbehaving and exhibiting weird errors in the last decimal places for things -// even as straightforward as -// -// double foo = 0.0; -// text >> foo. -// -// This comparison function works around that by allowing a small error band to pass the tests, but not enough to invalidate -// the tests on compilers that work. -bool comp_double(double lhs, double rhs) -{ - // Require exact match if 0=0. - if (std::min(lhs, rhs) == 0.0) { - return (lhs == rhs); - } else { - double unsigned_rel_error = std::abs(lhs - rhs) / std::min(lhs, rhs); - - return (unsigned_rel_error <= double {1e-8}); - } -} } // anonymous namespace // ----------------------------------------------------------------------------- @@ -225,7 +205,7 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_project_data) BOOST_CHECK(project.m_cpid == expected); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "url"); - BOOST_CHECK(comp_double(project.m_rac, 0.0)); + BOOST_CHECK(project.m_rac == 0.0); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); } @@ -254,7 +234,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_project_xml_string) BOOST_CHECK(project.m_cpid == cpid); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "https://example.com/"); - BOOST_CHECK(comp_double(project.m_rac, 123.45)); + BOOST_CHECK(project.m_rac == 123.45); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); // Clean up: @@ -289,7 +269,7 @@ BOOST_AUTO_TEST_CASE(it_falls_back_to_compute_a_missing_external_cpid) BOOST_CHECK(project.m_cpid == cpid); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "https://example.com/"); - BOOST_CHECK(comp_double(project.m_rac, 123.45)); + BOOST_CHECK(project.m_rac == 123.45); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); // Clean up: @@ -508,7 +488,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); BOOST_CHECK(project1->m_url == "https://example.com/1"); - BOOST_CHECK(comp_double(project1->m_rac, 123.45)); + BOOST_CHECK(project1->m_rac == 123.45); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { @@ -520,7 +500,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); BOOST_CHECK(project2->m_url == "https://example.com/2"); - BOOST_CHECK(comp_double(project2->m_rac, 567.89)); + BOOST_CHECK(project2->m_rac == 567.89); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -875,7 +855,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); BOOST_CHECK(project1->m_url == "https://example.com/1"); - BOOST_CHECK(comp_double(project1->m_rac, 1.1)); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { @@ -887,7 +867,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); BOOST_CHECK(project2->m_url == "https://example.com/2"); - BOOST_CHECK(comp_double(project2->m_rac, 2.2)); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -929,7 +909,7 @@ BOOST_AUTO_TEST_CASE(it_looks_up_loaded_boinc_projects_by_name) BOOST_CHECK(project->m_cpid == cpid); BOOST_CHECK(project->m_team == "gridcoin"); BOOST_CHECK(project->m_url == "https://example.com/"); - BOOST_CHECK(comp_double(project->m_rac, 1.1)); + BOOST_CHECK(project->m_rac == 1.1); BOOST_CHECK(project->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project->Eligible() == true); } else { @@ -1068,7 +1048,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "not gridcoin"); - BOOST_CHECK(comp_double(project1->m_rac, 1.1)); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project1->Eligible() == false); } else { @@ -1079,7 +1059,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project2->m_name == "project name 2"); BOOST_CHECK(project2->m_cpid == cpid); BOOST_CHECK(project2->m_team.empty() == true); - BOOST_CHECK(comp_double(project2->m_rac, 2.2)); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project2->Eligible() == false); } else { @@ -1090,7 +1070,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project3->m_name == "project name 3"); BOOST_CHECK(project3->m_cpid == GRC::Cpid()); BOOST_CHECK(project3->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project3->m_rac, 3.3)); + BOOST_CHECK(project3->m_rac == 3.3); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MALFORMED_CPID); BOOST_CHECK(project3->Eligible() == false); } else { @@ -1101,7 +1081,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project4->m_name == "project name 4"); BOOST_CHECK(project4->m_cpid == GRC::Cpid()); BOOST_CHECK(project4->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project4->m_rac, 4.4)); + BOOST_CHECK(project4->m_rac == 4.4); BOOST_CHECK(project4->m_error == GRC::MiningProject::Error::MALFORMED_CPID); BOOST_CHECK(project4->Eligible() == false); } else { @@ -1112,7 +1092,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project5->m_name == "project name 5"); BOOST_CHECK(project5->m_cpid == cpid); BOOST_CHECK(project5->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project5->m_rac, 5.5)); + BOOST_CHECK(project5->m_rac == 5.5); BOOST_CHECK(project5->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project5->Eligible() == false); } else { @@ -1123,7 +1103,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project6->m_name == "project name 6"); BOOST_CHECK(project6->m_cpid == cpid); BOOST_CHECK(project6->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project6->m_rac, 6.6)); + BOOST_CHECK(project6->m_rac == 6.6); BOOST_CHECK(project6->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project6->Eligible() == false); } else { @@ -1132,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) if (const GRC::ProjectOption project7 = projects.Try("project name 7")) { BOOST_CHECK(project7->m_name == "project name 7"); - BOOST_CHECK(comp_double(project7->m_rac, 7.7)); + BOOST_CHECK(project7->m_rac == 7.7); BOOST_CHECK(project7->m_error == GRC::MiningProject::Error::POOL); BOOST_CHECK(project7->Eligible() == false); } else { @@ -1142,7 +1122,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) if (const GRC::ProjectOption project8 = projects.Try("project name 8")) { BOOST_CHECK(project8->m_name == "project name 8"); BOOST_CHECK(project8->m_cpid.IsZero() == true); - BOOST_CHECK(comp_double(project8->m_rac, 8.8)); + BOOST_CHECK(project8->m_rac == 8.8); BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::POOL); BOOST_CHECK(project8->Eligible() == false); } else { @@ -1153,7 +1133,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project9->m_name == "project name 9"); BOOST_CHECK(project9->m_cpid == cpid); BOOST_CHECK(project9->m_team == "not gridcoin"); - BOOST_CHECK(comp_double(project9->m_rac, 0.0)); + BOOST_CHECK(project9->m_rac == 0.0); BOOST_CHECK(project9->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project9->Eligible() == false); } else { @@ -1232,7 +1212,7 @@ BOOST_AUTO_TEST_CASE(it_skips_the_team_requirement_when_set_by_protocol) BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "! not gridcoin !"); - BOOST_CHECK(comp_double(project1->m_rac, 1.1)); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { @@ -1302,7 +1282,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "! not gridcoin !"); - BOOST_CHECK(comp_double(project1->m_rac, 1.1)); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project1->Eligible() == false); } else { @@ -1313,7 +1293,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project2->m_name == "project name 2"); BOOST_CHECK(project2->m_cpid == cpid); BOOST_CHECK(project2->m_team == "team 1"); - BOOST_CHECK(comp_double(project2->m_rac, 0)); + BOOST_CHECK(project2->m_rac == 0); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -1324,7 +1304,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project3->m_name == "project name 3"); BOOST_CHECK(project3->m_cpid == cpid); BOOST_CHECK(project3->m_team == "team 2"); - BOOST_CHECK(comp_double(project3->m_rac, 0)); + BOOST_CHECK(project3->m_rac == 0); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project3->Eligible() == true); } else { @@ -1649,7 +1629,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project1->m_name == "valid project 1"); BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project1->m_rac, 1.1)); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_url == "https://project1.example.com/boinc/"); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); @@ -1661,7 +1641,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project2->m_name == "valid project 2"); BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project2->m_rac, 2.2)); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_url == "https://project2.example.com/boinc/"); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); @@ -1674,7 +1654,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project3->m_name == "invalid project 3"); BOOST_CHECK(project3->m_cpid == cpid_2); BOOST_CHECK(project3->m_team == "gridcoin"); - BOOST_CHECK(comp_double(project3->m_rac, 3.3)); + BOOST_CHECK(project3->m_rac == 3.3); BOOST_CHECK(project3->m_url == "https://project3.example.com/boinc/"); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project3->Eligible() == false); From 93d82b1baa2a3bbc31cb96a825743ebc31c113a3 Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 14:25:13 +0300 Subject: [PATCH 20/62] depends, build: pass BOOST_NO_CXX98_FUNCTION_BASE to Boost The class std::unary_function (which was deprecated in C++11, and removed in C++17) is finally removed in XCode 15, which causes compilation errors. This commits sets a macro which causes Boost to not use the aforementioned class. Port of upstream commit 880d4aaf81f3d5d7fbb915905c2e61b816a6a747 and d4c59da8d6e3aac14306249aa12332fed55efebd. --- configure.ac | 12 +++++++++++- depends/packages/boost.mk | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8fa47af3b0..8950d9c52f 100755 --- a/configure.ac +++ b/configure.ac @@ -1009,10 +1009,20 @@ dnl Check for Boost libs AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST]) AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM -AX_BOOST_THREAD AX_BOOST_ZLIB AX_BOOST_IOSTREAMS +dnl Prevent use of std::unary_function, which was removed in C++17, +dnl and will generate warnings with newer compilers for Boost +dnl older than 1.80. +dnl See: https://github.com/boostorg/config/pull/430. +AX_CHECK_PREPROC_FLAG([-DBOOST_NO_CXX98_FUNCTION_BASE], [BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE"], [], [$CXXFLAG_WERROR], + [AC_LANG_PROGRAM([[#include ]])]) + +dnl AX_BOOST_THREAD check also triggers the same issue, so it has to be checked after +dnl setting -DBOOST_NO_CXX98_FUNCTION_BASE. +AX_BOOST_THREAD + dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic dnl counter implementations. In 1.63 and later the std::atomic approach is default. m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index eef86df98a..a6f2dece64 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -28,7 +28,7 @@ ifneq (,$(findstring clang,$($(package)_cxx))) endif $(package)_archiver_$(host_os)=$($(package)_ar) $(package)_config_libraries=filesystem,system,thread,test,iostreams -$(package)_cxxflags+=-std=c++17 +$(package)_cxxflags+=-std=c++17 -DBOOST_NO_CXX98_FUNCTION_BASE $(package)_cxxflags_linux=-fPIC $(package)_cxxflags_android=-fPIC endef From a85c31ccb54736965ecc1e67f0f17b4a3b6e46f3 Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 14:35:33 +0300 Subject: [PATCH 21/62] depends: fix build issue with XCode 15 on Qt --- depends/packages/qt.mk | 2 + depends/patches/qt/fix-macos-linker.patch | 55 +++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 depends/patches/qt/fix-macos-linker.patch diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 3f721988a1..d92752496d 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -17,6 +17,7 @@ $(package)_patches += qtbase-moc-ignore-gcc-macro.patch $(package)_patches += no_qrhi.patch $(package)_patches += drop_lrelease_dependency.patch $(package)_patches += subdirs.pro +$(package)_patches += fix-macos-linker.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=c92af4171397a0ed272330b4fa0669790fcac8d050b07c8b8cc565ebeba6735e @@ -255,6 +256,7 @@ endef # CROSS_LIBRARY_PATH. See #15277. define $(package)_preprocess_cmds rm -f $(BASEDIR)/.qmake.stash && \ + patch -p1 -i $($(package)_patch_dir)/fix-macos-linker.patch && \ patch -p1 -i $($(package)_patch_dir)/drop_lrelease_dependency.patch && \ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.patch && \ diff --git a/depends/patches/qt/fix-macos-linker.patch b/depends/patches/qt/fix-macos-linker.patch new file mode 100644 index 0000000000..e439685656 --- /dev/null +++ b/depends/patches/qt/fix-macos-linker.patch @@ -0,0 +1,55 @@ +qmake: Don't error out if QMAKE_DEFAULT_LIBDIRS is empty on macOS + +The new linker in Xcode 15 doesn't provide any default linker or +framework paths when requested via -v, but still seems to use the +default paths documented in the ld man page. + +We trust that linker will do the right thing, even if we don't +know of its default linker paths. + +We also need to opt out of the default fallback logic to +set the libdirs to /lib and /usr/lib. + +This may result in UnixMakefileGenerator::findLibraries finding +different libraries than expected, if additional paths are +passed with -L, which will then take precedence for qmake, +even if the linker itself will use the library from the +SDK's default paths. This should hopefully not be an issue +in practice, as we don't turn -lFoo into absolute paths in +qmake, so the only risk is that we're picking up the wrong +prl files and adding additional dependencies that the lib +in the SDK doesn't have. + +Upstream commits: + - Qt 5.15.16: Not yet publicly available. + - Qt dev: cdf64b0e47115cc473e1afd1472b4b09e130b2a5 + +For other Qt branches see +https://codereview.qt-project.org/q/I2347b26e2df0828471373b0e15b8c9089274c65d + +--- old/qtbase/mkspecs/features/toolchain.prf ++++ new/qtbase/mkspecs/features/toolchain.prf +@@ -288,9 +288,12 @@ isEmpty($${target_prefix}.INCDIRS) { + } + } + } +- isEmpty(QMAKE_DEFAULT_LIBDIRS)|isEmpty(QMAKE_DEFAULT_INCDIRS): \ ++ isEmpty(QMAKE_DEFAULT_INCDIRS): \ + !integrity: \ +- error("failed to parse default search paths from compiler output") ++ error("failed to parse default include paths from compiler output") ++ isEmpty(QMAKE_DEFAULT_LIBDIRS): \ ++ !integrity:!darwin: \ ++ error("failed to parse default library paths from compiler output") + QMAKE_DEFAULT_LIBDIRS = $$unique(QMAKE_DEFAULT_LIBDIRS) + } else: ghs { + cmd = $$QMAKE_CXX $$QMAKE_CXXFLAGS -$${LITERAL_HASH} -o /tmp/fake_output /tmp/fake_input.cpp +@@ -412,7 +415,7 @@ isEmpty($${target_prefix}.INCDIRS) { + QMAKE_DEFAULT_INCDIRS = $$split(INCLUDE, $$QMAKE_DIRLIST_SEP) + } + +- unix:if(!cross_compile|host_build) { ++ unix:!darwin:if(!cross_compile|host_build) { + isEmpty(QMAKE_DEFAULT_INCDIRS): QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include + isEmpty(QMAKE_DEFAULT_LIBDIRS): QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib + } From b84ee2395d79c8bcf27d9a2e22dc54df95cb233d Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 15:14:50 +0300 Subject: [PATCH 22/62] depends: force -j1 during staging phase of libzip Parallel jobs can cause libzip to have a race condition on mkdir on Darwin. --- depends/packages/libzip.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/libzip.mk b/depends/packages/libzip.mk index 11ffdd414b..507d768ad2 100644 --- a/depends/packages/libzip.mk +++ b/depends/packages/libzip.mk @@ -42,5 +42,5 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install + $(MAKE) DESTDIR=$($(package)_staging_dir) install -j1 endef From bb44b2c27d2ccb5f5b591a4f169fbeb2760e6c10 Mon Sep 17 00:00:00 2001 From: Matthias Bach Date: Tue, 5 Mar 2024 08:42:06 +0100 Subject: [PATCH 23/62] Fix man page installation path for cmake builds The standard layout for man pages is for them to be stored in subdirectories based on the section they belong to. --- src/CMakeLists.txt | 2 +- src/qt/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 479d210bee..d458b210d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -266,7 +266,7 @@ if(ENABLE_DAEMON) DESTINATION "${CMAKE_INSTALL_BINDIR}" ) install(FILES "${CMAKE_SOURCE_DIR}/doc/gridcoinresearchd.1" - DESTINATION "${CMAKE_INSTALL_MANDIR}" + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" ) install(FILES "${CMAKE_SOURCE_DIR}/contrib/init/gridcoinresearchd.service" DESTINATION /lib/systemd/system diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 9a763d4e37..888fec44fe 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -194,7 +194,7 @@ if(UNIX AND NOT APPLE) DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" ) install(FILES "${CMAKE_SOURCE_DIR}/doc/gridcoinresearch.1" - DESTINATION "${CMAKE_INSTALL_MANDIR}" + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" ) endif() From d9de40e0f0f6a191c0c7b4bd365660469032f4d6 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:20:46 +0300 Subject: [PATCH 24/62] build: add option for sanitizers --- configure.ac | 36 ++++++++++++++++++++++++++++++++++++ src/Makefile.am | 4 ++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8fa47af3b0..9afa9ba822 100755 --- a/configure.ac +++ b/configure.ac @@ -209,6 +209,12 @@ AC_ARG_ENABLE([debug], [enable_debug=$enableval], [enable_debug=no]) +dnl Enable different -fsanitize options +AC_ARG_WITH([sanitizers], + [AS_HELP_STRING([--with-sanitizers], + [comma separated list of extra sanitizers to build with (default is none enabled)])], + [use_sanitizers=$withval]) + # Turn warnings into errors AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], @@ -230,6 +236,33 @@ if test "$enable_debug" = "yes"; then fi fi +if test "$use_sanitizers" != ""; then + dnl First check if the compiler accepts flags. If an incompatible pair like + dnl -fsanitize=address,thread is used here, this check will fail. This will also + dnl fail if a bad argument is passed, e.g. -fsanitize=undfeined + AX_CHECK_COMPILE_FLAG( + [-fsanitize=$use_sanitizers], + [SANITIZER_CXXFLAGS="-fsanitize=$use_sanitizers"], + [AC_MSG_ERROR([compiler did not accept requested flags])]) + + dnl Some compilers (e.g. GCC) require additional libraries like libasan, + dnl libtsan, libubsan, etc. Make sure linking still works with the sanitize + dnl flag. This is a separate check so we can give a better error message when + dnl the sanitize flags are supported by the compiler but the actual sanitizer + dnl libs are missing. + AX_CHECK_LINK_FLAG( + [-fsanitize=$use_sanitizers], + [SANITIZER_LDFLAGS="-fsanitize=$use_sanitizers"], + [AC_MSG_ERROR([linker did not accept requested flags, you are missing required libraries])], + [], + [AC_LANG_PROGRAM([[ + #include + #include + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { return 0; } + __attribute__((weak)) // allow for libFuzzer linking + ]],[[]])]) +fi + ERROR_CXXFLAGS= if test "$enable_werror" = "yes"; then if test "$CXXFLAG_WERROR" = ""; then @@ -1292,6 +1325,8 @@ AC_SUBST(HARDENED_CPPFLAGS) AC_SUBST(HARDENED_LDFLAGS) AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) +AC_SUBST(SANITIZER_CXXFLAGS) +AC_SUBST(SANITIZER_LDFLAGS) AC_SUBST(SSE42_CXXFLAGS) AC_SUBST(SSE41_CXXFLAGS) AC_SUBST(AVX2_CXXFLAGS) @@ -1398,6 +1433,7 @@ echo " with zmq = $use_zmq" echo " with test = $use_tests" echo " with bench = $use_bench" echo " with upnp = $use_upnp" +echo " sanitizers = $use_sanitizers" echo " debug enabled = $enable_debug" echo " werror = $enable_werror" echo diff --git a/src/Makefile.am b/src/Makefile.am index c521bd11fe..b92061afbc 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,8 +8,8 @@ print-%: FORCE DIST_SUBDIRS = univalue secp256k1 -AM_LDFLAGS = ${libcurl_LIBS} $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) +AM_LDFLAGS = ${libcurl_LIBS} $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(SANITIZER_LDFLAGS) +AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) $(SANITIZER_CXXFLAGS) AM_CPPFLAGS = ${libcurl_CFLAGS} $(HARDENED_CPPFLAGS) -DSTATICLIB -DCURL_STATICLIB -DMINIUPNP_STATICLIB -DZIP_STATIC -DNN_STATIC_LIB EXTRA_LIBRARIES = From 00d6ae75fdaffcd716923e125448391ab7de6202 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sat, 30 Jul 2022 02:44:07 +0300 Subject: [PATCH 25/62] misc: fix UB in CPID hashing --- src/gridcoin/cpid.h | 18 +++++++++++++----- src/test/gridcoin/cpid_tests.cpp | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/gridcoin/cpid.h b/src/gridcoin/cpid.h index b644abbd8c..c8b3df5417 100644 --- a/src/gridcoin/cpid.h +++ b/src/gridcoin/cpid.h @@ -454,9 +454,9 @@ namespace std { //! This enables the use of GRC::Cpid as a key in a std::unordered_map object. //! //! CONSENSUS: Don't use the hash produced by this routine (or by any std::hash -//! specialization) in protocol-specific implementations. It ignores endianness -//! and outputs a value with a chance of collision probably too great for usage -//! besides the intended local look-up functionality. +//! specialization) in protocol-specific implementations. It outputs a value +//! with a chance of collision probably too great for usage besides the intended +//! local look-up functionality. //! template<> struct hash @@ -473,8 +473,16 @@ struct hash // Just convert the CPID into a value that we can store in a size_t // object. CPIDs are already unique identifiers. // - return *reinterpret_cast(cpid.Raw().data()) - + *reinterpret_cast(cpid.Raw().data() + 8); + const auto& data = cpid.Raw(); + size_t ret = ((size_t)(data[0] & 255) | (size_t)(data[1] & 255) << 8 | + (size_t)(data[2] & 255) << 16 | (size_t)(data[3] & 255) << 24); + + if (sizeof(size_t) == 8) { + ret |= ((size_t)(data[4] & 255) << 32 | (size_t)(data[5] & 255) << 40 | + (size_t)(data[6] & 255) << 48 | (size_t)(data[7] & 255) << 56); + } + + return ret; } }; } diff --git a/src/test/gridcoin/cpid_tests.cpp b/src/test/gridcoin/cpid_tests.cpp index 6becf0cc51..c76af4f76a 100644 --- a/src/test/gridcoin/cpid_tests.cpp +++ b/src/test/gridcoin/cpid_tests.cpp @@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(it_is_hashable_to_key_a_lookup_map) std::hash hasher; // CPID halves, little endian - const size_t expected = static_cast(0x0706050403020100ull + 0x1514131211100908ull); + const size_t expected = static_cast(0x0706050403020100ull); BOOST_CHECK_EQUAL(hasher(cpid), expected); } From e33bc3589cb777f1f486e2da0849ac4661d53502 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sun, 16 Oct 2022 02:04:22 +0300 Subject: [PATCH 26/62] ci: add new builds with sanitizers --- .github/workflows/ci.yml | 4 ++++ ci/test/00_setup_env_native_asan.sh | 14 ++++++++++++++ ci/test/00_setup_env_native_tsan.sh | 14 ++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 ci/test/00_setup_env_native_asan.sh create mode 100644 ci/test/00_setup_env_native_tsan.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ddd104cac..6b3488812b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,10 @@ jobs: script-id: native - name: x86_64 Linux [GOAL install] [GUI] [bionic] [no depends] script-id: native_old + - name: x86_64 Linux [ASan] [LSan] [UBSan] [integer] [jammy] [no depends] + script-id: native_asan + - name: x86_64 Linux [TSan] [GUI] [jammy] + script-id: native_tsan - name: macOS 10.14 [GOAL deploy] [GUI] [no tests] [focal] script-id: mac env: diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh new file mode 100644 index 0000000000..4426072659 --- /dev/null +++ b/ci/test/00_setup_env_native_asan.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_native_asan +export PACKAGES="clang llvm libqt5gui5 libqt5core5a qtbase5-dev libqt5dbus5 qttools5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-iostreams-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libqrencode-dev libzip-dev zlib1g zlib1g-dev libcurl4 libcurl4-openssl-dev" +export DOCKER_NAME_TAG=ubuntu:22.04 +export NO_DEPENDS=1 +export GOAL="install" +export GRIDCOIN_CONFIG="--with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh new file mode 100644 index 0000000000..206af61e08 --- /dev/null +++ b/ci/test/00_setup_env_native_tsan.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_native_tsan +export DOCKER_NAME_TAG=ubuntu:22.04 +export PACKAGES="clang-13 llvm-13 libc++abi-13-dev libc++-13-dev" +export DEP_OPTS="CC=clang-13 CXX='clang++-13 -stdlib=libc++'" +export GOAL="install" +export GRIDCOIN_CONFIG="CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread CC=clang-13 CXX='clang++-13 -stdlib=libc++'" From 57251db5017ab0f3bc9d2ac4279a4d4cf495c227 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sun, 16 Oct 2022 11:47:10 +0300 Subject: [PATCH 27/62] support: add proper includes for -DARENA_DEBUG --- src/support/lockedpool.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index a2b03b3eab..2162ccb80d 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -24,6 +24,10 @@ #include #include +#ifdef ARENA_DEBUG +#include +#include +#endif LockedPoolManager* LockedPoolManager::_instance = nullptr; std::once_flag LockedPoolManager::init_flag; From 19731eee716a1ec6f953f0980ed5f39496b7e3be Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sun, 16 Oct 2022 13:29:36 +0300 Subject: [PATCH 28/62] support: fix compilation with -DARENA_DEBUG --- src/support/lockedpool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 2162ccb80d..979f0705a4 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -154,7 +154,7 @@ void Arena::walk() const printchunk(chunk.first, chunk.second, true); std::cout << std::endl; for (const auto& chunk: chunks_free) - printchunk(chunk.first, chunk.second, false); + printchunk(chunk.first, chunk.second->first, false); std::cout << std::endl; } #endif From c927e0025826cff7dd09389b905f601797dd054c Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:39:04 +0300 Subject: [PATCH 29/62] ci: disable tsan job Rationale: The thread sanitizer CI job uses clang which has issues with compiling Qt on Linux. Disable for now until the issue can be fixed. --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b3488812b..ad48da6b7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,9 @@ jobs: script-id: native_old - name: x86_64 Linux [ASan] [LSan] [UBSan] [integer] [jammy] [no depends] script-id: native_asan - - name: x86_64 Linux [TSan] [GUI] [jammy] - script-id: native_tsan + # FIXME: depends is unable to compile Qt with clang. + # - name: x86_64 Linux [TSan] [GUI] [jammy] + # script-id: native_tsan - name: macOS 10.14 [GOAL deploy] [GUI] [no tests] [focal] script-id: mac env: From 29a0c093e418442b80ac1313e3e8ec9c5a2be127 Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 31 Jul 2023 18:44:26 +0300 Subject: [PATCH 30/62] ci: use suppression files for sanitizers --- ci/test/04_install.sh | 5 +++ test/sanitizer_suppressions/lsan | 2 + test/sanitizer_suppressions/tsan | 45 +++++++++++++++++++++++ test/sanitizer_suppressions/ubsan | 61 +++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 test/sanitizer_suppressions/lsan create mode 100644 test/sanitizer_suppressions/tsan create mode 100644 test/sanitizer_suppressions/ubsan diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh index 288f60a7d5..d1ba771f6a 100755 --- a/ci/test/04_install.sh +++ b/ci/test/04_install.sh @@ -17,6 +17,11 @@ fi mkdir -p "${CCACHE_DIR}" mkdir -p "${PREVIOUS_RELEASES_DIR}" +export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" +export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan" +export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:halt_on_error=1:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan" +export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1" + env | grep -E '^(GRIDCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|DEBIAN_FRONTEND|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|PREVIOUS_RELEASES_DIR)' | tee /tmp/env if [[ $HOST = *-mingw32 ]]; then DOCKER_ADMIN="--cap-add SYS_ADMIN" diff --git a/test/sanitizer_suppressions/lsan b/test/sanitizer_suppressions/lsan new file mode 100644 index 0000000000..7ccb22515f --- /dev/null +++ b/test/sanitizer_suppressions/lsan @@ -0,0 +1,2 @@ +# Suppress warnings triggered in dependencies +leak:libQt5Widgets diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan new file mode 100644 index 0000000000..82c6885bc4 --- /dev/null +++ b/test/sanitizer_suppressions/tsan @@ -0,0 +1,45 @@ +# ThreadSanitizer suppressions +# ============================ +# +# https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions + +# race (TODO fix) +race:LoadWallet +race:WalletBatch::WriteHDChain +race:BerkeleyBatch +race:BerkeleyDatabase +race:DatabaseBatch +race:zmq::* +race:bitcoin-qt + +# deadlock (TODO fix) +# To reproduce, see: +# https://github.com/bitcoin/bitcoin/issues/19303#issuecomment-1514926359 +deadlock:Chainstate::ConnectTip + +# Intentional deadlock in tests +deadlock:sync_tests::potential_deadlock_detected + +# Wildcard for all gui tests, should be replaced with non-wildcard suppressions +race:src/qt/test/* +deadlock:src/qt/test/* + +# External libraries +# https://github.com/bitcoin/bitcoin/pull/27658#issuecomment-1547639621 +deadlock:libdb +race:libzmq + +# Intermittent issues +# ------------------- +# +# Suppressions that follow might only happen intermittently, thus they are not +# reproducible. Make sure to include a link to a full trace. + +# https://github.com/bitcoin/bitcoin/issues/20618 +race:CZMQAbstractPublishNotifier::SendZmqMessage + +# https://github.com/bitcoin/bitcoin/pull/27498#issuecomment-1517410478 +race:epoll_ctl + +# https://github.com/bitcoin/bitcoin/issues/23366 +race:std::__1::ios_base::* diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan new file mode 100644 index 0000000000..68f2bee322 --- /dev/null +++ b/test/sanitizer_suppressions/ubsan @@ -0,0 +1,61 @@ +# Suppressions should use `sanitize-type:ClassName::MethodName`. + +# -fsanitize=undefined suppressions +# ================================= + +# -fsanitize=integer suppressions +# =============================== +# Dependencies +# ------------ +# Suppressions in dependencies that are developed outside this repository. +unsigned-integer-overflow:*/include/c++/ +unsigned-integer-overflow:FuzzedDataProvider::ConsumeIntegralInRange +unsigned-integer-overflow:leveldb/ +unsigned-integer-overflow:minisketch/ +unsigned-integer-overflow:test/fuzz/crypto_diff_fuzz_chacha20.cpp +implicit-integer-sign-change:*/include/boost/ +implicit-integer-sign-change:*/include/c++/ +implicit-integer-sign-change:*/new_allocator.h +implicit-integer-sign-change:crc32c/ +implicit-integer-sign-change:minisketch/ +implicit-signed-integer-truncation:*/include/c++/ +implicit-signed-integer-truncation:leveldb/ +implicit-unsigned-integer-truncation:*/include/c++/ +implicit-unsigned-integer-truncation:leveldb/ +implicit-unsigned-integer-truncation:test/fuzz/crypto_diff_fuzz_chacha20.cpp +shift-base:*/include/c++/ +shift-base:leveldb/ +shift-base:minisketch/ +shift-base:test/fuzz/crypto_diff_fuzz_chacha20.cpp +# Unsigned integer overflow occurs when the result of an unsigned integer +# computation cannot be represented in its type. Unlike signed integer overflow, +# this is not undefined behavior, but it is often unintentional. The list below +# contains files in which we expect unsigned integer overflows to occur. The +# list is used to suppress -fsanitize=integer warnings when running our CI UBSan +# job. +unsigned-integer-overflow:arith_uint256.h +unsigned-integer-overflow:common/bloom.cpp +unsigned-integer-overflow:coins.cpp +unsigned-integer-overflow:compressor.cpp +unsigned-integer-overflow:crypto/ +unsigned-integer-overflow:hash.cpp +unsigned-integer-overflow:policy/fees.cpp +unsigned-integer-overflow:prevector.h +unsigned-integer-overflow:script/interpreter.cpp +unsigned-integer-overflow:xoroshiro128plusplus.h +implicit-integer-sign-change:compat/stdin.cpp +implicit-integer-sign-change:compressor.h +implicit-integer-sign-change:crypto/ +implicit-integer-sign-change:policy/fees.cpp +implicit-integer-sign-change:prevector.h +implicit-integer-sign-change:script/bitcoinconsensus.cpp +implicit-integer-sign-change:script/interpreter.cpp +implicit-integer-sign-change:serialize.h +implicit-signed-integer-truncation:crypto/ +implicit-unsigned-integer-truncation:crypto/ +shift-base:arith_uint256.cpp +shift-base:crypto/ +shift-base:hash.cpp +shift-base:streams.h +shift-base:util/bip32.cpp +shift-base:xoroshiro128plusplus.h From c39f895391a66083a12693be70f955d2a0ba74a1 Mon Sep 17 00:00:00 2001 From: div72 Date: Thu, 7 Dec 2023 23:07:15 +0300 Subject: [PATCH 31/62] Fix memory leak in wallet tests --- src/test/wallet_tests.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index c5e390e531..a741d2a127 100755 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -13,6 +13,8 @@ using namespace std; +std::vector> wtxn; + typedef set > CoinSet; BOOST_AUTO_TEST_SUITE(wallet_tests) @@ -23,13 +25,12 @@ static vector vCoins; static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { static int i; - CTransaction* tx = new CTransaction; - tx->nLockTime = i++; // so all transactions get different hashes - tx->nTime = 0; - tx->vout.resize(nInput+1); - tx->vout[nInput].nValue = nValue; - CWalletTx* wtx = new CWalletTx(&wallet, *tx); - delete tx; + CTransaction tx; + tx.nLockTime = i++; // so all transactions get different hashes + tx.nTime = 0; + tx.vout.resize(nInput+1); + tx.vout[nInput].nValue = nValue; + std::unique_ptr wtx(new CWalletTx(&wallet, tx)); if (fIsFromMe) { // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(), @@ -38,15 +39,15 @@ static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, in wtx->fDebitCached = true; wtx->nDebitCached = 1; } - COutput output(wtx, nInput, nAge); + COutput output(wtx.get(), nInput, nAge); vCoins.push_back(output); + wtxn.emplace_back(std::move(wtx)); } static void empty_wallet() { - for(COutput& output : vCoins) - delete output.tx; vCoins.clear(); + wtxn.clear(); } static bool equal_sets(CoinSet a, CoinSet b) @@ -298,6 +299,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) BOOST_CHECK_NE(fails, RANDOM_REPEATS); } } + empty_wallet(); } BOOST_AUTO_TEST_SUITE_END() From 66967f0e80c28a8254106b06389a98cdc93cb7e9 Mon Sep 17 00:00:00 2001 From: div72 Date: Thu, 7 Dec 2023 23:10:48 +0300 Subject: [PATCH 32/62] miner: don't leak CBlockIndex used for testing --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index bc0ef2deb7..387e891a53 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -310,8 +310,8 @@ bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev, int nHeight = pindexPrev->nHeight + 1; // This is specifically for BlockValidateContracts, and only the nHeight is filled in. - CBlockIndex* pindex_contract_validate = new CBlockIndex(); - pindex_contract_validate->nHeight = nHeight; + CBlockIndex pindex_contract_validate; + pindex_contract_validate.nHeight = nHeight; // Create coinbase tx CTransaction &CoinBase = block.vtx[0]; @@ -385,7 +385,7 @@ bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev, // pindex_contract_validate only has the block height filled out. // int DoS = 0; // Unused here. - if (!tx.GetContracts().empty() && !GRC::BlockValidateContracts(pindex_contract_validate, tx, DoS)) { + if (!tx.GetContracts().empty() && !GRC::BlockValidateContracts(&pindex_contract_validate, tx, DoS)) { LogPrint(BCLog::LogFlags::MINER, "%s: contract failed contextual validation. Skipped tx %s", __func__, From cfcfe24078d8e9b13e1d99873df18faaa67c7970 Mon Sep 17 00:00:00 2001 From: div72 Date: Thu, 7 Dec 2023 23:18:01 +0300 Subject: [PATCH 33/62] test: free wallet at exit of mrc_tests --- src/test/gridcoin/mrc_tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/gridcoin/mrc_tests.cpp b/src/test/gridcoin/mrc_tests.cpp index 4a427fd3be..779d957b3f 100644 --- a/src/test/gridcoin/mrc_tests.cpp +++ b/src/test/gridcoin/mrc_tests.cpp @@ -103,6 +103,7 @@ struct Setup { mapBlockIndex.erase(pindexGenesisBlock->GetBlockHash()); delete pindexGenesisBlock->phashBlock; + delete wallet; } }; } // Anonymous namespace From 6fd9480d4daafaa8c0537edbe638d5b3f385763e Mon Sep 17 00:00:00 2001 From: div72 Date: Fri, 8 Dec 2023 00:44:55 +0300 Subject: [PATCH 34/62] test: cleanup leveldb env Rationale: Some classes in LevelDB do not get freed unless the environment is deleted. --- src/test/test_gridcoin.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/test_gridcoin.cpp b/src/test/test_gridcoin.cpp index cacb3e12ec..7a9f325e3d 100644 --- a/src/test/test_gridcoin.cpp +++ b/src/test/test_gridcoin.cpp @@ -14,6 +14,8 @@ #include "random.h" #include "wallet/wallet.h" +leveldb::Env* txdb_env; + extern CWallet* pwalletMain; extern leveldb::DB *txdb; extern CClientUIInterface uiInterface; @@ -48,7 +50,7 @@ struct TestingSetup { // TODO: Refactor CTxDB to something like bitcoin's current CDBWrapper and remove this workaround. leveldb::Options db_options; - db_options.env = leveldb::NewMemEnv(leveldb::Env::Default()); // Use a memory environment to avoid polluting the production leveldb. + db_options.env = txdb_env = leveldb::NewMemEnv(leveldb::Env::Default()); // Use a memory environment to avoid polluting the production leveldb. db_options.create_if_missing = true; db_options.error_if_exists = true; assert(leveldb::DB::Open(db_options, "", &txdb).ok()); @@ -71,7 +73,9 @@ struct TestingSetup { bitdb.Flush(true); g_banman.reset(); delete txdb; + delete txdb_env; txdb = nullptr; + txdb_env = nullptr; g_mock_deterministic_tests = false; ECC_Stop(); } From c4262686c958c175d97e967bf5a555a899108593 Mon Sep 17 00:00:00 2001 From: div72 Date: Sun, 24 Dec 2023 22:59:20 +0300 Subject: [PATCH 35/62] mrc: zero initialize primitives Rationale: Avoids an UB in it_rejects_invalid_claims MRC test. --- src/gridcoin/mrc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gridcoin/mrc.h b/src/gridcoin/mrc.h index bcc966d036..578c631302 100644 --- a/src/gridcoin/mrc.h +++ b/src/gridcoin/mrc.h @@ -125,14 +125,14 @@ class MRC : public IContractPayload //! incoming reward claims and can index those calculated values without //! this field. It can be considered informational. //! - CAmount m_research_subsidy; + CAmount m_research_subsidy = 0; //! //! \brief The value of the fees charged to the MRC claimant. These will be //! subtracted from the research subsidy and distributed to the staker and //! the foundation according to protocol rules encapsulated in ComputeMRCFee(). //! - CAmount m_fee; + CAmount m_fee = 0; //! //! \brief The researcher magnitude value from the superblock at the time @@ -145,14 +145,14 @@ class MRC : public IContractPayload //! //! Previous protocol versions used the magnitude in reward calculations. //! - uint16_t m_magnitude; + uint16_t m_magnitude = 0; //! //! \brief The magnitude ratio of the network at the time of the claim. //! //! Informational. //! - double m_magnitude_unit; + double m_magnitude_unit = 0.0; //! //! \brief The hash of the last block (head of the chain) for the MRC From 29d6adbb4ba8cb979294aa416b850cfaa7794b22 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Sat, 16 Nov 2019 10:40:16 -0800 Subject: [PATCH 36/62] Fix segfault in allocator_tests/arena_tests The test uses reinterpret_cast on unallocated memory. Using this memory in printchunk as char* causes a segfault, so have printchunk take void* instead. --- src/support/lockedpool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 979f0705a4..ef05f222b6 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -142,7 +142,7 @@ Arena::Stats Arena::stats() const } #ifdef ARENA_DEBUG -static void printchunk(char* base, size_t sz, bool used) { +static void printchunk(void* base, size_t sz, bool used) { std::cout << "0x" << std::hex << std::setw(16) << std::setfill('0') << base << " 0x" << std::hex << std::setw(16) << std::setfill('0') << sz << From 8a6579357329938290eec495ac537bfd69e83a53 Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 26 Dec 2023 16:53:45 +0300 Subject: [PATCH 37/62] test: fix suppression for script.cpp --- test/sanitizer_suppressions/ubsan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 68f2bee322..600d2dc8a2 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -41,7 +41,7 @@ unsigned-integer-overflow:crypto/ unsigned-integer-overflow:hash.cpp unsigned-integer-overflow:policy/fees.cpp unsigned-integer-overflow:prevector.h -unsigned-integer-overflow:script/interpreter.cpp +unsigned-integer-overflow:script.cpp unsigned-integer-overflow:xoroshiro128plusplus.h implicit-integer-sign-change:compat/stdin.cpp implicit-integer-sign-change:compressor.h @@ -49,7 +49,7 @@ implicit-integer-sign-change:crypto/ implicit-integer-sign-change:policy/fees.cpp implicit-integer-sign-change:prevector.h implicit-integer-sign-change:script/bitcoinconsensus.cpp -implicit-integer-sign-change:script/interpreter.cpp +implicit-integer-sign-change:script.cpp implicit-integer-sign-change:serialize.h implicit-signed-integer-truncation:crypto/ implicit-unsigned-integer-truncation:crypto/ From 14ec4af47f136a8f8cd72a291a7025879c12a9fe Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 15:50:21 +0300 Subject: [PATCH 38/62] test: fix memory leaks in beacon tests --- src/test/gridcoin/beacon_tests.cpp | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/test/gridcoin/beacon_tests.cpp b/src/test/gridcoin/beacon_tests.cpp index e216919f3a..770cddb0d7 100644 --- a/src/test/gridcoin/beacon_tests.cpp +++ b/src/test/gridcoin/beacon_tests.cpp @@ -1268,10 +1268,10 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test) tx1.nTime = int64_t {1}; uint256 tx1_hash = tx1.GetHash(); - CBlockIndex* pindex1 = new CBlockIndex; - pindex1->nVersion = 13; - pindex1->nHeight = 1; - pindex1->nTime = tx1.nTime; + CBlockIndex pindex1 {}; + pindex1.nVersion = 13; + pindex1.nHeight = 1; + pindex1.nTime = tx1.nTime; GRC::Beacon beacon1 {TestKey::Public(), tx1.nTime, tx1_hash}; beacon1.m_cpid = TestKey::Cpid(); @@ -1280,7 +1280,7 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test) beacon_payload1.m_signature = TestKey::Signature(beacon_payload1); GRC::Contract contract1 = GRC::MakeContract(3, GRC::ContractAction::ADD, beacon_payload1); - GRC::ContractContext ctx1 {contract1, tx1, pindex1}; + GRC::ContractContext ctx1 {contract1, tx1, &pindex1}; BOOST_CHECK(ctx1.m_contract.CopyPayloadAs().m_cpid == TestKey::Cpid()); BOOST_CHECK(ctx1.m_contract.CopyPayloadAs().m_beacon.m_status == GRC::BeaconStatusForStorage::PENDING); @@ -1305,18 +1305,18 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test) } // Activation - CBlockIndex* pindex2 = new CBlockIndex; - pindex2->nVersion = 13; - pindex2->nHeight = 2; - pindex2->nTime = int64_t {2}; - uint256* block2_phash = new uint256 {rng.rand256()}; - pindex2->phashBlock = block2_phash; + CBlockIndex pindex2 {}; + pindex2.nVersion = 13; + pindex2.nHeight = 2; + pindex2.nTime = int64_t {2}; + uint256 block2_phash = rng.rand256(); + pindex2.phashBlock = &block2_phash; std::vector beacon_ids {TestKey::Public().GetID()}; - registry.ActivatePending(beacon_ids, pindex2->nTime, *pindex2->phashBlock, pindex2->nHeight); + registry.ActivatePending(beacon_ids, pindex2.nTime, *pindex2.phashBlock, pindex2.nHeight); - uint256 activated_beacon_hash = Hash(*block2_phash, pending_beacons[0]->m_hash); + uint256 activated_beacon_hash = Hash(block2_phash, pending_beacons[0]->m_hash); BOOST_CHECK(registry.GetBeaconDB().size() == 2); @@ -1475,10 +1475,10 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test_2) tx1.nTime = int64_t {1}; uint256 tx1_hash = tx1.GetHash(); - CBlockIndex* pindex1 = new CBlockIndex; - pindex1->nVersion = 13; - pindex1->nHeight = 1; - pindex1->nTime = tx1.nTime; + CBlockIndex pindex1 {}; + pindex1.nVersion = 13; + pindex1.nHeight = 1; + pindex1.nTime = tx1.nTime; GRC::Beacon beacon1 {TestKey::Public(), tx1.nTime, tx1_hash}; beacon1.m_cpid = TestKey::Cpid(); @@ -1487,7 +1487,7 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test_2) beacon_payload1.m_signature = TestKey::Signature(beacon_payload1); GRC::Contract contract1 = GRC::MakeContract(3, GRC::ContractAction::ADD, beacon_payload1); - GRC::ContractContext ctx1 {contract1, tx1, pindex1}; + GRC::ContractContext ctx1 {contract1, tx1, &pindex1}; BOOST_CHECK(ctx1.m_contract.CopyPayloadAs().m_cpid == TestKey::Cpid()); BOOST_CHECK(ctx1.m_contract.CopyPayloadAs().m_beacon.m_status == GRC::BeaconStatusForStorage::PENDING); @@ -1512,18 +1512,18 @@ BOOST_AUTO_TEST_CASE(beacon_registry_GetBeaconChainletRoot_test_2) } // Activation - CBlockIndex* pindex2 = new CBlockIndex; - pindex2->nVersion = 13; - pindex2->nHeight = 2; - pindex2->nTime = int64_t {2}; - uint256* block2_phash = new uint256 {rng.rand256()}; - pindex2->phashBlock = block2_phash; + CBlockIndex pindex2 {}; + pindex2.nVersion = 13; + pindex2.nHeight = 2; + pindex2.nTime = int64_t {2}; + uint256 block2_phash = rng.rand256(); + pindex2.phashBlock = &block2_phash; std::vector beacon_ids {TestKey::Public().GetID()}; - registry.ActivatePending(beacon_ids, pindex2->nTime, *pindex2->phashBlock, pindex2->nHeight); + registry.ActivatePending(beacon_ids, pindex2.nTime, *pindex2.phashBlock, pindex2.nHeight); - uint256 activated_beacon_hash = Hash(*block2_phash, pending_beacons[0]->m_hash); + uint256 activated_beacon_hash = Hash(block2_phash, pending_beacons[0]->m_hash); BOOST_CHECK(registry.GetBeaconDB().size() == 2); From d73c0cf93eca7e3f763a51fc16a5ab2c1e50ba06 Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 15:56:55 +0300 Subject: [PATCH 39/62] test: fix integer underflow in accounting tests --- src/test/accounting_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 50259351a1..a89a266fbf 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -78,13 +78,13 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) wtx.mapValue["comment"] = "y"; - --wtx.nLockTime; // Just to change the hash :) + ++wtx.nLockTime; // Just to change the hash :) pwalletMain->AddToWallet(wtx, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[1]->nTimeReceived = (unsigned int)1333333336; wtx.mapValue["comment"] = "x"; - --wtx.nLockTime; // Just to change the hash :) + ++wtx.nLockTime; // Just to change the hash :) pwalletMain->AddToWallet(wtx, &walletdb); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[2]->nTimeReceived = (unsigned int)1333333329; From 28986ad22f2db11cc54b524e2100432fcad31d6f Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 16:24:30 +0300 Subject: [PATCH 40/62] refactor: make CBlockIndex nflags enum unsigned --- src/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.h b/src/main.h index 5af4e3e47a..a204117097 100644 --- a/src/main.h +++ b/src/main.h @@ -478,7 +478,7 @@ class CBlockIndex int nHeight; unsigned int nFlags; // ppcoin: block index flags - enum + enum : uint32_t { BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier From 7cd0247b4d0f2e0b1e1d273351b926441cceeee0 Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 4 Mar 2024 16:24:51 +0300 Subject: [PATCH 41/62] scraper: remove redundant cntPartsRcvd inc/decrement --- src/gridcoin/scraper/scraper_net.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gridcoin/scraper/scraper_net.cpp b/src/gridcoin/scraper/scraper_net.cpp index 25cc1360e4..e00fb4d9e4 100644 --- a/src/gridcoin/scraper/scraper_net.cpp +++ b/src/gridcoin/scraper/scraper_net.cpp @@ -139,9 +139,7 @@ int CSplitBlob::addPartData(CDataStream&& vData) { /* missing data; use the supplied data */ /* prevent calling the Complete callback FIXME: make this look better */ - cntPartsRcvd--; CSplitBlob::RecvPart(nullptr, vData); - cntPartsRcvd++; } return n; } From 6e922877ae53c0a71c03ad712b6b433e43ae0f42 Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 5 Mar 2024 13:24:06 +0300 Subject: [PATCH 42/62] superblock: eliminate UB during binary magnitude extraction --- src/gridcoin/superblock.cpp | 5 +++-- src/test/gridcoin/superblock_tests.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gridcoin/superblock.cpp b/src/gridcoin/superblock.cpp index 4b9e7c61d7..c2f8251de6 100644 --- a/src/gridcoin/superblock.cpp +++ b/src/gridcoin/superblock.cpp @@ -456,8 +456,9 @@ class LegacySuperblockParser for (size_t x = 0; x < binary_size && binary_size - x >= 18; x += 18) { magnitudes.AddLegacy( - *reinterpret_cast(byte_ptr + x), - be16toh(*reinterpret_cast(byte_ptr + x + 16))); + Cpid(std::vector(byte_ptr + x, byte_ptr + x + 16)), + (((uint16_t)byte_ptr[x + 16] & 0xFF) << 8) | ((uint16_t)byte_ptr[x + 17] & 0xFF) + ); } return magnitudes; diff --git a/src/test/gridcoin/superblock_tests.cpp b/src/test/gridcoin/superblock_tests.cpp index 61a8a7642c..eea417b628 100644 --- a/src/test/gridcoin/superblock_tests.cpp +++ b/src/test/gridcoin/superblock_tests.cpp @@ -33,7 +33,7 @@ struct Legacy struct BinaryResearcher { std::array cpid; - int16_t magnitude; + uint16_t magnitude; }; static std::string ExtractValue(std::string data, std::string delimiter, int pos) From 2c233c1f4a152c96fc782d39004b3174427a6d92 Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 5 Mar 2024 14:17:59 +0300 Subject: [PATCH 43/62] util: avoid underflow in SplitHostPort --- src/util/strencodings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index db89881f26..d2f0a4852f 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -112,7 +112,7 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator bool fHaveColon = colon != in.npos; bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe - bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos); + bool fMultiColon = fHaveColon && (colon != 0) && (in.find_last_of(':',colon-1) != in.npos); if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) { int32_t n; if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) { From 8be87712216a3183fb7a086d04e43b79ffed1be8 Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 5 Mar 2024 14:18:09 +0300 Subject: [PATCH 44/62] refactor: port upstream changes for merkle --- src/consensus/merkle.cpp | 130 ++++---------------------------------- src/consensus/merkle.h | 12 +--- src/test/merkle_tests.cpp | 123 ++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 127 deletions(-) diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index 7d15d9d52c..7fbe05adf8 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -37,118 +37,25 @@ root. */ -/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ -static void MerkleComputation(const std::vector& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector* pbranch) { - if (pbranch) pbranch->clear(); - if (leaves.size() == 0) { - if (pmutated) *pmutated = false; - if (proot) *proot = uint256(); - return; - } - bool mutated = false; - // count is the number of leaves processed so far. - uint32_t count = 0; - // inner is an array of eagerly computed subtree hashes, indexed by tree - // level (0 being the leaves). - // For example, when count is 25 (11001 in binary), inner[4] is the hash of - // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to - // the last leaf. The other inner entries are undefined. - uint256 inner[32]; - // Which position in inner is a hash that depends on the matching leaf. - int matchlevel = -1; - // First process all leaves into 'inner' values. - while (count < leaves.size()) { - uint256 h = leaves[count]; - bool matchh = count == branchpos; - count++; - int level; - // For each of the lower bits in count that are 0, do 1 step. Each - // corresponds to an inner value that existed before processing the - // current leaf, and each needs a hash to combine it. - for (level = 0; !(count & (((uint32_t)1) << level)); level++) { - if (pbranch) { - if (matchh) { - pbranch->push_back(inner[level]); - } else if (matchlevel == level) { - pbranch->push_back(h); - matchh = true; - } +uint256 ComputeMerkleRoot(std::vector hashes, bool* mutated) { + bool mutation = false; + while (hashes.size() > 1) { + if (mutated) { + for (size_t pos = 0; pos + 1 < hashes.size(); pos += 2) { + if (hashes[pos] == hashes[pos + 1]) mutation = true; } - mutated |= (inner[level] == h); - CHash256().Write(inner[level]).Write(h).Finalize(h); - } - // Store the resulting hash at inner position level. - inner[level] = h; - if (matchh) { - matchlevel = level; - } - } - // Do a final 'sweep' over the rightmost branch of the tree to process - // odd levels, and reduce everything to a single top value. - // Level is the level (counted from the bottom) up to which we've sweeped. - int level = 0; - // As long as bit number level in count is zero, skip it. It means there - // is nothing left at this level. - while (!(count & (((uint32_t)1) << level))) { - level++; - } - uint256 h = inner[level]; - bool matchh = matchlevel == level; - while (count != (((uint32_t)1) << level)) { - // If we reach this point, h is an inner value that is not the top. - // We combine it with itself (Bitcoin's special rule for odd levels in - // the tree) to produce a higher level one. - if (pbranch && matchh) { - pbranch->push_back(h); } - CHash256().Write(h).Write(h).Finalize(h); - // Increment count to the value it would have if two entries at this - // level had existed. - count += (((uint32_t)1) << level); - level++; - // And propagate the result upwards accordingly. - while (!(count & (((uint32_t)1) << level))) { - if (pbranch) { - if (matchh) { - pbranch->push_back(inner[level]); - } else if (matchlevel == level) { - pbranch->push_back(h); - matchh = true; - } - } - CHash256().Write(inner[level]).Write(h).Finalize(h); - level++; + if (hashes.size() & 1) { + hashes.push_back(hashes.back()); } + SHA256D64(hashes[0].begin(), hashes[0].begin(), hashes.size() / 2); + hashes.resize(hashes.size() / 2); } - // Return result. - if (pmutated) *pmutated = mutated; - if (proot) *proot = h; -} - -uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated) { - uint256 hash; - MerkleComputation(leaves, &hash, mutated, -1, nullptr); - return hash; -} - -std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position) { - std::vector ret; - MerkleComputation(leaves, nullptr, nullptr, position, &ret); - return ret; + if (mutated) *mutated = mutation; + if (hashes.size() == 0) return uint256(); + return hashes[0]; } -uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& vMerkleBranch, uint32_t nIndex) { - uint256 hash = leaf; - for (std::vector::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { - if (nIndex & 1) { - hash = Hash(*it, hash); - } else { - hash = Hash(hash, *it); - } - nIndex >>= 1; - } - return hash; -} uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) { @@ -157,15 +64,6 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) for (size_t s = 0; s < block.vtx.size(); s++) { leaves[s] = block.vtx[s].GetHash(); } - return ComputeMerkleRoot(leaves, mutated); + return ComputeMerkleRoot(std::move(leaves), mutated); } -std::vector BlockMerkleBranch(const CBlock& block, uint32_t position) -{ - std::vector leaves; - leaves.resize(block.vtx.size()); - for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetHash(); - } - return ComputeMerkleBranch(leaves, position); -} diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h index 439e60ed30..beb78eeeda 100644 --- a/src/consensus/merkle.h +++ b/src/consensus/merkle.h @@ -5,15 +5,12 @@ #ifndef BITCOIN_CONSENSUS_MERKLE_H #define BITCOIN_CONSENSUS_MERKLE_H -#include #include #include "main.h" #include -uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated = nullptr); -std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position); -uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& branch, uint32_t position); +uint256 ComputeMerkleRoot(std::vector leaves, bool* mutated = nullptr); /* * Compute the Merkle root of the transactions in a block. @@ -21,11 +18,4 @@ uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector BlockMerkleBranch(const CBlock& block, uint32_t position); - #endif // BITCOIN_CONSENSUS_MERKLE_H diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 36463d42d6..4fc02a1818 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -9,6 +9,129 @@ BOOST_AUTO_TEST_SUITE(merkle_tests) +/* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ +static void MerkleComputation(const std::vector& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector* pbranch) { + if (pbranch) pbranch->clear(); + if (leaves.size() == 0) { + if (pmutated) *pmutated = false; + if (proot) *proot = uint256(); + return; + } + bool mutated = false; + // count is the number of leaves processed so far. + uint32_t count = 0; + // inner is an array of eagerly computed subtree hashes, indexed by tree + // level (0 being the leaves). + // For example, when count is 25 (11001 in binary), inner[4] is the hash of + // the first 16 leaves, inner[3] of the next 8 leaves, and inner[0] equal to + // the last leaf. The other inner entries are undefined. + uint256 inner[32]; + // Which position in inner is a hash that depends on the matching leaf. + int matchlevel = -1; + // First process all leaves into 'inner' values. + while (count < leaves.size()) { + uint256 h = leaves[count]; + bool matchh = count == branchpos; + count++; + int level; + // For each of the lower bits in count that are 0, do 1 step. Each + // corresponds to an inner value that existed before processing the + // current leaf, and each needs a hash to combine it. + for (level = 0; !(count & (((uint32_t)1) << level)); level++) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + mutated |= (inner[level] == h); + CHash256().Write(inner[level]).Write(h).Finalize(h); + } + // Store the resulting hash at inner position level. + inner[level] = h; + if (matchh) { + matchlevel = level; + } + } + // Do a final 'sweep' over the rightmost branch of the tree to process + // odd levels, and reduce everything to a single top value. + // Level is the level (counted from the bottom) up to which we've sweeped. + int level = 0; + // As long as bit number level in count is zero, skip it. It means there + // is nothing left at this level. + while (!(count & (((uint32_t)1) << level))) { + level++; + } + uint256 h = inner[level]; + bool matchh = matchlevel == level; + while (count != (((uint32_t)1) << level)) { + // If we reach this point, h is an inner value that is not the top. + // We combine it with itself (Bitcoin's special rule for odd levels in + // the tree) to produce a higher level one. + if (pbranch && matchh) { + pbranch->push_back(h); + } + CHash256().Write(h).Write(h).Finalize(h); + // Increment count to the value it would have if two entries at this + // level had existed. + count += (((uint32_t)1) << level); + level++; + // And propagate the result upwards accordingly. + while (!(count & (((uint32_t)1) << level))) { + if (pbranch) { + if (matchh) { + pbranch->push_back(inner[level]); + } else if (matchlevel == level) { + pbranch->push_back(h); + matchh = true; + } + } + CHash256().Write(inner[level]).Write(h).Finalize(h); + level++; + } + } + // Return result. + if (pmutated) *pmutated = mutated; + if (proot) *proot = h; +} + +uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated) { + uint256 hash; + MerkleComputation(leaves, &hash, mutated, -1, nullptr); + return hash; +} + +std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position) { + std::vector ret; + MerkleComputation(leaves, nullptr, nullptr, position, &ret); + return ret; +} + +uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& vMerkleBranch, uint32_t nIndex) { + uint256 hash = leaf; + for (std::vector::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { + if (nIndex & 1) { + hash = Hash(*it, hash); + } else { + hash = Hash(hash, *it); + } + nIndex >>= 1; + } + return hash; +} + +std::vector BlockMerkleBranch(const CBlock& block, uint32_t position) +{ + std::vector leaves; + leaves.resize(block.vtx.size()); + for (size_t s = 0; s < block.vtx.size(); s++) { + leaves[s] = block.vtx[s].GetHash(); + } + return ComputeMerkleBranch(leaves, position); +} + // Older version of the merkle root computation code, for comparison. static uint256 BlockBuildMerkleTree(const CBlock& block, std::vector& vMerkleTree) { From 08f65b865cc092c41ceceb966243db78eec81a0f Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 5 Mar 2024 14:33:38 +0300 Subject: [PATCH 45/62] refactor: make uint32_t casts explicit in tx tests --- src/test/transaction_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 26809b7214..dbb899992f 100755 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + COutPoint outpoint(uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())); mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); } @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) fValid = false; break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + COutPoint outpoint(uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())); mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); } if (!fValid) From 0e8552dc13a9e26132a8ad74caf87d65261cd153 Mon Sep 17 00:00:00 2001 From: div72 Date: Tue, 5 Mar 2024 14:44:30 +0300 Subject: [PATCH 46/62] test: make int64_t casts explicit in msb tests --- src/test/util_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 5ccb4fc05e..1aeccd2785 100755 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1173,7 +1173,7 @@ BOOST_AUTO_TEST_CASE(Fraction_msb_performance_test) g_timer.InitTimer("msb_test", true); for (unsigned int i = 0; i < iterations; ++i) { - msb(rand.rand64()); + msb((int64_t)rand.rand64()); } int64_t msb_test_time = g_timer.GetTimes(strprintf("msb %u iterations", iterations), "msb_test").time_since_last_check; @@ -1181,7 +1181,7 @@ BOOST_AUTO_TEST_CASE(Fraction_msb_performance_test) FastRandomContext rand2(uint256 {0}); for (unsigned int i = 0; i < iterations; ++i) { - msb2(rand2.rand64()); + msb2((int64_t)rand2.rand64()); } int64_t msb2_test_time = g_timer.GetTimes(strprintf("msb2 %u iterations", iterations), "msb_test").time_since_last_check; @@ -1189,7 +1189,7 @@ BOOST_AUTO_TEST_CASE(Fraction_msb_performance_test) FastRandomContext rand3(uint256 {0}); for (unsigned int i = 0; i < iterations; ++i) { - msb3(rand3.rand64()); + msb3((int64_t)rand3.rand64()); } int64_t msb3_test_time = g_timer.GetTimes(strprintf("msb3 %u iterations", iterations), "msb_test").time_since_last_check; From 493b739a5d435d8c242fc422eef033ac2e85379c Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 6 Mar 2024 15:51:26 -0500 Subject: [PATCH 47/62] Increment version to 5.4.6.2 for development --- CMakeLists.txt | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5d2b8b1dc..d9c4eaa380 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.18) project("Gridcoin" - VERSION 5.4.6.1 + VERSION 5.4.6.2 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" LANGUAGES ASM C CXX diff --git a/configure.ac b/configure.ac index 8fa47af3b0..6c688de7c7 100755 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_IS_RELEASE, false) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) From a16718ff8da16bdb4985655999694900dafefe2f Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 13 Mar 2024 15:40:57 -0400 Subject: [PATCH 48/62] Increment version to 5.4.7.1 for development. --- CMakeLists.txt | 4 ++-- configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0836128949..999227935e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,13 +9,13 @@ cmake_minimum_required(VERSION 3.18) project("Gridcoin" - VERSION 5.4.7.0 + VERSION 5.4.7.1 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" LANGUAGES ASM C CXX ) -set(CLIENT_VERSION_IS_RELEASE "true") +set(CLIENT_VERSION_IS_RELEASE "false") set(COPYRIGHT_YEAR "2024") set(COPYRIGHT_HOLDERS_FINAL "The Gridcoin developers") diff --git a/configure.ac b/configure.ac index d1a2c0e319..b9943ee673 100755 --- a/configure.ac +++ b/configure.ac @@ -3,8 +3,8 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 7) -define(_CLIENT_VERSION_BUILD, 0) -define(_CLIENT_VERSION_IS_RELEASE, true) +define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_IS_RELEASE, false) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Gridcoin]]) From 4b8557f7867541bc8d870d16255aa1a79c2466d3 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sun, 17 Mar 2024 21:37:21 -0400 Subject: [PATCH 49/62] Cast 0 to uint32_t in SetStakeEntropyBit conditional This eliminates the compiler warning about enumerated vs non-enumerated type in conditional. --- src/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.h b/src/main.h index a204117097..3afe3e45a5 100644 --- a/src/main.h +++ b/src/main.h @@ -630,7 +630,7 @@ class CBlockIndex { if (nEntropyBit > 1) return false; - nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0); + nFlags |= (nEntropyBit ? BLOCK_STAKE_ENTROPY : (uint32_t) 0); return true; } From bc30bd87d4f4b5ffdb1799a2c0d517230f90a16b Mon Sep 17 00:00:00 2001 From: Matthias Bach Date: Mon, 18 Mar 2024 21:32:29 +0100 Subject: [PATCH 50/62] Fix Systemd unit install location The Systemd unit file should be installed relative to the install prefix, not at an absolute path. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d458b210d4..e7fcf641cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -269,7 +269,7 @@ if(ENABLE_DAEMON) DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" ) install(FILES "${CMAKE_SOURCE_DIR}/contrib/init/gridcoinresearchd.service" - DESTINATION /lib/systemd/system + DESTINATION "lib/systemd/system" ) endif() endif() From 58177452b1ec5c68bf921497cae84547008e6fe5 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Fri, 29 Mar 2024 10:28:24 -0400 Subject: [PATCH 51/62] Corrections to scraper_net after removal of cntPartsRcvd decrement and increment Includes fixes to address premature marking of manifests complete that was being masked by decrementing an unsigned integer that was already zero. --- src/gridcoin/scraper/scraper.cpp | 7 ++++--- src/gridcoin/scraper/scraper_net.cpp | 12 ++++++++---- src/gridcoin/scraper/scraper_net.h | 7 ++++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/gridcoin/scraper/scraper.cpp b/src/gridcoin/scraper/scraper.cpp index 9a65484b78..d654f88d4a 100755 --- a/src/gridcoin/scraper/scraper.cpp +++ b/src/gridcoin/scraper/scraper.cpp @@ -4479,7 +4479,7 @@ EXCLUSIVE_LOCKS_REQUIRED(cs_StructScraperFileManifest, CScraperManifest::cs_mapM CDataStream part(std::move(vchData), SER_NETWORK, 1); - manifest->addPartData(std::move(part)); + manifest->addPartData(std::move(part), true); iPartNum++; @@ -4512,7 +4512,7 @@ EXCLUSIVE_LOCKS_REQUIRED(cs_StructScraperFileManifest, CScraperManifest::cs_mapM part << ScraperVerifiedBeacons.mVerifiedMap; - manifest->addPartData(std::move(part)); + manifest->addPartData(std::move(part), true); iPartNum++; } @@ -4592,7 +4592,7 @@ EXCLUSIVE_LOCKS_REQUIRED(cs_StructScraperFileManifest, CScraperManifest::cs_mapM CDataStream part(vchData, SER_NETWORK, 1); - manifest->addPartData(std::move(part)); + manifest->addPartData(std::move(part), true); iPartNum++; } @@ -4602,6 +4602,7 @@ EXCLUSIVE_LOCKS_REQUIRED(cs_StructScraperFileManifest, CScraperManifest::cs_mapM LOCK(CSplitBlob::cs_mapParts); + // addManifest will also call Complete() after signing to send the manifest over the network. bool bAddManifestSuccessful = CScraperManifest::addManifest(manifest, Key); if (bAddManifestSuccessful) diff --git a/src/gridcoin/scraper/scraper_net.cpp b/src/gridcoin/scraper/scraper_net.cpp index e00fb4d9e4..ccb46dc9f2 100644 --- a/src/gridcoin/scraper/scraper_net.cpp +++ b/src/gridcoin/scraper/scraper_net.cpp @@ -97,7 +97,7 @@ bool CSplitBlob::RecvPart(CNode* pfrom, CDataStream& vRecv) bool CSplitBlob::isComplete() const EXCLUSIVE_LOCKS_REQUIRED(CSplitBlob::cs_manifest) { - return cntPartsRcvd == vParts.size(); + return (!m_publish_in_progress && cntPartsRcvd == vParts.size()); } void CSplitBlob::addPart(const uint256& ihash) @@ -119,10 +119,12 @@ void CSplitBlob::addPart(const uint256& ihash) part.refs.emplace(this, n); } -int CSplitBlob::addPartData(CDataStream&& vData) +int CSplitBlob::addPartData(CDataStream&& vData, const bool& publish_in_progress) { LOCK2(cs_mapParts, cs_manifest); + m_publish_in_progress = publish_in_progress; + uint256 hash(Hash(vData)); auto it = mapParts.emplace(hash, CPart(hash)); @@ -138,9 +140,9 @@ int CSplitBlob::addPartData(CDataStream&& vData) if (!part.present()) { /* missing data; use the supplied data */ - /* prevent calling the Complete callback FIXME: make this look better */ CSplitBlob::RecvPart(nullptr, vData); } + return n; } @@ -800,7 +802,7 @@ EXCLUSIVE_LOCKS_REQUIRED(CScraperManifest::cs_mapManifest, cs_mapParts) if (it.second == false) return false; - // Release lock on cs_manifest before taking a lonk on cs_ConvergedScraperStatsCache to avoid potential deadlocks. + // Release lock on cs_manifest before taking a lock on cs_ConvergedScraperStatsCache to avoid potential deadlocks. { CScraperManifest& manifest = *it.first->second; @@ -834,6 +836,8 @@ EXCLUSIVE_LOCKS_REQUIRED(CScraperManifest::cs_mapManifest, cs_mapParts) void CScraperManifest::Complete() EXCLUSIVE_LOCKS_REQUIRED(CSplitBlob::cs_manifest, CSplitBlob::cs_mapParts) { + m_publish_in_progress = false; + // Notify peers that we have a new manifest LogPrint(BCLog::LogFlags::MANIFEST, "manifest %s complete with %u parts", phash->GetHex(), (unsigned)vParts.size()); { diff --git a/src/gridcoin/scraper/scraper_net.h b/src/gridcoin/scraper/scraper_net.h index 3959a6e889..ed2b1681a9 100755 --- a/src/gridcoin/scraper/scraper_net.h +++ b/src/gridcoin/scraper/scraper_net.h @@ -65,7 +65,7 @@ class CSplitBlob void addPart(const uint256& ihash); /** Create a part from specified data and add reference to it into vParts. */ - int addPartData(CDataStream&& vData); + int addPartData(CDataStream&& vData, const bool &publish_in_progress = false); /** Unref all parts referenced by this. Removes parts with no references */ virtual ~CSplitBlob(); @@ -86,6 +86,11 @@ class CSplitBlob std::vector vParts GUARDED_BY(cs_manifest); size_t cntPartsRcvd GUARDED_BY(cs_manifest) = 0; + + //! + //! \brief Used by the scraper when building manifests part by part to prevent triggering Complete() prematurely. + //! + bool m_publish_in_progress GUARDED_BY(cs_manifest) = false; }; /** An objects holding info about the scraper data file we have or are downloading. */ From b2af56a293397b8376d0397f2fc1e7fa50d4ce27 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sun, 10 Mar 2024 21:24:53 -0400 Subject: [PATCH 52/62] Add listmandatorysidestakes rpc --- src/gridcoin/sidestake.cpp | 27 +++++++++++++++++++++++++++ src/gridcoin/sidestake.h | 15 +++++++++++++++ src/rpc/blockchain.cpp | 35 +++++++++++++++++++++++++++++++++++ src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + 5 files changed, 79 insertions(+) diff --git a/src/gridcoin/sidestake.cpp b/src/gridcoin/sidestake.cpp index f96bd840db..2c9e53966d 100644 --- a/src/gridcoin/sidestake.cpp +++ b/src/gridcoin/sidestake.cpp @@ -453,6 +453,33 @@ std::string SideStake::GetDescription() const return std::string {}; } +int64_t SideStake::GetTimeStamp() const +{ + if (m_type == Type::MANDATORY && m_mandatory_sidestake_ptr != nullptr) { + return m_mandatory_sidestake_ptr->m_timestamp; + } + + return int64_t {0}; +} + +uint256 SideStake::GetHash() const +{ + if (m_type == Type::MANDATORY && m_mandatory_sidestake_ptr != nullptr) { + return m_mandatory_sidestake_ptr->m_hash; + } + + return uint256 {}; +} + +uint256 SideStake::GetPreviousHash() const +{ + if (m_type == Type::MANDATORY && m_mandatory_sidestake_ptr != nullptr) { + return m_mandatory_sidestake_ptr->m_previous_hash; + } + + return uint256 {}; +} + SideStake::Status SideStake::GetStatus() const { // For trivial initializer case diff --git a/src/gridcoin/sidestake.h b/src/gridcoin/sidestake.h index 42613e938c..2737085e6c 100644 --- a/src/gridcoin/sidestake.h +++ b/src/gridcoin/sidestake.h @@ -428,6 +428,21 @@ class SideStake //! std::string GetDescription() const; //! + //! \brief Gets the timestamp of the transaction that contains the mandatory sidestake contract (now entry) + //! \return + //! + int64_t GetTimeStamp() const; + //! + //! \brief Gets the hash of the transaction that contains the mandatory sidestake contract (now entry) + //! \return uint256 hash + //! + uint256 GetHash() const; + //! + //! \brief Gets the hash of the transaction that contains the previous mandatory sidestake contract for the same key (address) + //! \return uint256 hash + //! + uint256 GetPreviousHash() const; + //! //! \brief Gets a variant containing either the mandatory sidestake status or local sidestake status, whichever //! is applicable. //! \return std::variant of the applicable sidestake status diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 8c3964a9a4..32ee83380c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2700,6 +2700,41 @@ UniValue listprotocolentries(const UniValue& params, bool fHelp) return res; } +UniValue listmandatorysidestakes(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "listprotocolentries\n" + "\n" + "Displays the mandatory sidestakes on the network.\n"); + + UniValue res(UniValue::VOBJ); + UniValue scraper_entries(UniValue::VARR); + + for (const auto& sidestake : GRC::GetSideStakeRegistry().ActiveSideStakeEntries(GRC::SideStake::FilterFlag::MANDATORY, false)) { + UniValue entry(UniValue::VOBJ); + + entry.pushKV("mandatory_sidestake_entry_address", CBitcoinAddress(sidestake->GetDestination()).ToString()); + entry.pushKV("mandatory_sidestake_entry_allocation", sidestake->GetAllocation().ToPercent()); + entry.pushKV("mandatory_sidestake_entry_tx_hash", sidestake->GetHash().ToString()); + if (sidestake->GetPreviousHash().IsNull()) { + entry.pushKV("previous_mandatory_sidestake_entry_tx_hash", "null"); + } else { + entry.pushKV("previous_mandatory_sidestake_entry_tx_hash", sidestake->GetPreviousHash().ToString()); + } + + entry.pushKV("mandatory_sidestake_entry_timestamp", sidestake->GetTimeStamp()); + entry.pushKV("mandatory_sidestake_entry_time", DateTimeStrFormat(sidestake->GetTimeStamp())); + entry.pushKV("mandatory_sidestake_entry_status", sidestake->StatusToString()); + + scraper_entries.push_back(entry); + } + + res.pushKV("current_mandatory_sidestake_entries", scraper_entries); + + return res; +} + UniValue network(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5bf4a69b26..08640a3d93 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -388,6 +388,7 @@ static const CRPCCommand vRPCCommands[] = { "listprotocolentries", &listprotocolentries, cat_developer }, { "listresearcheraccounts", &listresearcheraccounts, cat_developer }, { "listscrapers", &listscrapers, cat_developer }, + { "listmandatorysidestakes", &listmandatorysidestakes, cat_developer }, { "listsettings", &listsettings, cat_developer }, { "logging", &logging, cat_developer }, { "network", &network, cat_developer }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 6aa1c4850f..a4b6f2d571 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -199,6 +199,7 @@ extern UniValue listprojects(const UniValue& params, bool fHelp); extern UniValue listprotocolentries(const UniValue& params, bool fHelp); extern UniValue listresearcheraccounts(const UniValue& params, bool fHelp); extern UniValue listscrapers(const UniValue& params, bool fHelp); +extern UniValue listmandatorysidestakes(const UniValue& params, bool fHelp); extern UniValue listsettings(const UniValue& params, bool fHelp); extern UniValue logging(const UniValue& params, bool fHelp); extern UniValue network(const UniValue& params, bool fHelp); From a8899f561c9a808b51a5e1d5ec6615bb82a6fee9 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Mon, 11 Mar 2024 02:18:13 -0400 Subject: [PATCH 53/62] Add missing mrc fees to reward used for SplitCoinStakeOutput In V13 testing with simultaneous mrcs and mandatory sidestakes, stakes were being rejected because the calculated total reward to the staker did not include mrc fees. This apparently has been an existing omission, but since sidestakes were not validated it went undetected. Now that mandatory sidestakes are validated in terms of both destination and amount, they were being rejected by the validator as being too low. Adding the mrc fees due to the staker to the staker's reward fixes the problem. --- src/miner.cpp | 38 +++++++++++++++++++++++++++------ src/miner.h | 1 + src/test/gridcoin/mrc_tests.cpp | 2 +- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 387e891a53..1d1e8a3f7f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -150,7 +150,7 @@ bool TrySignClaim( // This is in anonymous namespace because it is only to be used by miner code here in this file. bool CreateMRCRewards(CBlock &blocknew, std::map>& mrc_map, - std::map& mrc_tx_map, uint32_t& claim_contract_version, + std::map& mrc_tx_map, CAmount& reward, uint32_t& claim_contract_version, GRC::Claim& claim, CWallet* pwallet) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { // For convenience @@ -160,7 +160,7 @@ bool CreateMRCRewards(CBlock &blocknew, std::map 0) { // TODO: Make foundation address a defaulted but protocol overridable parameter. @@ -287,7 +290,7 @@ bool CreateMRCRewards(CBlock &blocknew, std::map( @@ -1439,7 +1442,8 @@ void StakeMiner(CWallet *pwallet) // * Add MRC outputs to coinstake. This has to be done before the coinstake splitting/sidestaking, because // Some of the MRC fees go to the miner as part of the reward, and this affects the SplitCoinStakeOutput calculation. - if (!CreateMRCRewards(StakeBlock, mrc_map, mrc_tx_map, claim_contract_version, claim, pwallet)) continue; + // Note that nReward here now includes the mrc fees to the staker. + if (!CreateMRCRewards(StakeBlock, mrc_map, mrc_tx_map, nReward, claim_contract_version, claim, pwallet)) continue; g_timer.GetTimes(function + "CreateMRC", "miner"); @@ -1467,6 +1471,28 @@ void StakeMiner(CWallet *pwallet) g_miner_status.IncrementBlocksCreated(); + if (LogInstance().WillLogCategory(BCLog::LogFlags::VERBOSE)) { + COutPoint stake_prevout = StakeBlock.vtx[1].vin[0].prevout; + CTransaction stake_input; + ReadTxFromDisk(stake_input, stake_prevout); + + LogPrintf("INFO: %s: stake input = %s", + __func__, + FormatMoney(stake_input.vout[stake_prevout.n].nValue)); + + for (unsigned int i = 1; i < StakeBlock.vtx[1].vout.size(); ++i) { + CTxDestination destination; + + ExtractDestination(StakeBlock.vtx[1].vout[i].scriptPubKey, destination); + + LogPrintf("INFO: %s: stake output[%u] = %s, destination = %s", + __func__, + i, + FormatMoney(StakeBlock.vtx[1].vout[i].nValue), + CBitcoinAddress(destination).ToString()); + } + } + // * delegate to ProcessBlock if (!ProcessBlock(nullptr, &StakeBlock, true)) { error("%s: Block vehemently rejected", __func__); diff --git a/src/miner.h b/src/miner.h index c713a8de89..6e439c099a 100644 --- a/src/miner.h +++ b/src/miner.h @@ -31,6 +31,7 @@ bool GetStakeSplitStatusAndParams(int64_t& nMinStakeSplitValue, double& dEfficie bool CreateMRCRewards(CBlock &blocknew, std::map>& mrc_map, std::map& mrc_tx_map, + CAmount& reward, uint32_t& claim_contract_version, GRC::Claim& claim, CWallet* pwallet) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/test/gridcoin/mrc_tests.cpp b/src/test/gridcoin/mrc_tests.cpp index 779d957b3f..f80c5c4495 100644 --- a/src/test/gridcoin/mrc_tests.cpp +++ b/src/test/gridcoin/mrc_tests.cpp @@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(it_creates_valid_mrc_claims) BOOST_CHECK(CreateGridcoinReward(block, pindex->pprev, reward, claim)); - BOOST_CHECK(CreateMRCRewards(block, mrc_map, mrc_tx_map, claim_contract_version, claim, wallet)); + BOOST_CHECK(CreateMRCRewards(block, mrc_map, mrc_tx_map, reward, claim_contract_version, claim, wallet)); // TODO(div72): Separate this test into pieces and actually have it do // some useful testing by testing the validation logic against it. From 745db52d4e4ae9822191654aa7cb3df0184d6272 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 3 Apr 2024 11:10:34 -0400 Subject: [PATCH 54/62] Update checkpoint data for mainnet and testnet --- src/chainparams.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index fa9e268052..53d8ca56d8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -150,6 +150,8 @@ class CMainParams : public CChainParams { {2400000, uint256S("0xf67b595e02e22a02498dfab853e2fabe6e74298a8d83ddc6115c37eaa5808bf6")}, {2600000, uint256S("0xc86624a7f4dde5046d9b62aa2e177a46c60845684702ea3fd49ff40f4f2418f6")}, {2800000, uint256S("0x09af79c7da8880f7aa56687baf59f35a9d489037f3271938f85b3317d08a8476")}, + {3000000, uint256S("0xc991e619995b65af5af5fe13bb8d61d60c8bb0f4eb2f1472abc058c7aac28a13")}, + {3200000, uint256S("0xbf56ac3d117b7e24ca9d2082961a53bb4f77cd43eaa2a036628c97d2e1bc0cd2")}, } }; @@ -220,7 +222,8 @@ class CTestNetParams : public CChainParams { checkpointData = { { - {0, uint256S("00006e037d7b84104208ecf2a8638d23149d712ea810da604ee2f2cb39bae713")}, + {0, uint256S("0x00006e037d7b84104208ecf2a8638d23149d712ea810da604ee2f2cb39bae713")}, + {2400000, uint256S("0x962b7607f8ffceb5c77951d242caed3f94f465f8529d924338700895ff8ed458")}, } }; From 055abe2fd3962ea0474ec552ff092e8aa050f3d4 Mon Sep 17 00:00:00 2001 From: div72 Date: Fri, 5 Apr 2024 00:08:34 +0300 Subject: [PATCH 55/62] rpc: check for return of LookupHost Not checking can cause a segfault if LookupHost fails. --- src/rpc/net.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 65180d6139..13127761d3 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -241,8 +241,9 @@ UniValue setban(const UniValue& params, bool fHelp) if (!isSubnet) { std::vector resolved; - LookupHost(params[0].get_str().c_str(), resolved, 1, false); - netAddr = resolved[0]; + if (LookupHost(params[0].get_str().c_str(), resolved, 1, false)) { + netAddr = resolved[0]; + } } else LookupSubNet(params[0].get_str().c_str(), subNet); From 47bb53dcabbff55337c52ea36aff45b34eff7d28 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Fri, 5 Apr 2024 15:56:27 -0400 Subject: [PATCH 56/62] Enhance verify checkpoints fail handling This changes the verify checkpoints fail handling to use the GUI reset blockchain facility if in the GUI, or direct the user to use the -resetblockchaindata option if using the daemon, rather than instructing the user to manually delete the blockchain data files. --- src/gridcoin/gridcoin.cpp | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/gridcoin/gridcoin.cpp b/src/gridcoin/gridcoin.cpp index 39853e113f..b9292896d5 100644 --- a/src/gridcoin/gridcoin.cpp +++ b/src/gridcoin/gridcoin.cpp @@ -27,6 +27,7 @@ extern bool fExplorer; extern unsigned int nScraperSleep; extern unsigned int nActiveBeforeSB; extern bool fScraperActive; +extern bool fQtActive; void Scraper(bool bSingleShot = false); void ScraperSubscriber(); @@ -40,17 +41,29 @@ namespace { //! void ShowChainCorruptedMessage() { - uiInterface.ThreadSafeMessageBox( - _("WARNING: Blockchain data may be corrupted.\n\n" - "Gridcoin detected bad index entries. This may occur because of an " - "unexpected exit, a power failure, or a late software upgrade.\n\n" - "Please exit Gridcoin, open the data directory, and delete:\n" - " - the blk****.dat files\n" - " - the txleveldb folder\n\n" - "Your wallet will re-download the blockchain. Your balance may " - "appear incorrect until the synchronization finishes.\n" ), - "Gridcoin", - CClientUIInterface::BTN_OK | CClientUIInterface::MODAL); + fResetBlockchainRequest = true; + + if (fQtActive) { + uiInterface.ThreadSafeMessageBox( + _("ERROR: Checkpoint mismatch: Blockchain data may be corrupted.\n\n" + "Gridcoin detected bad index entries. This may occur because of a " + "late software upgrade, unexpected exit, or a power failure. " + "Your blockchain data is being reset and your wallet will resync " + "from genesis when you restart. Your balance may appear incorrect " + "until the synchronization finishes."), + "Gridcoin", + CClientUIInterface::BTN_OK | CClientUIInterface::MODAL); + } else { + uiInterface.ThreadSafeMessageBox( + _("ERROR: Checkpoint mismatch: Blockchain data may be corrupted.\n\n" + "Gridcoin detected bad index entries. This may occur because of a " + "late software upgrade, unexpected exit, or a power failure. " + "Please run gridcoinresearchd with the -resetblockchaindata " + "parameter. Your wallet will re-download the blockchain. Your " + "balance may appear incorrect until the synchronization finishes." ), + "Gridcoin", + CClientUIInterface::BTN_OK | CClientUIInterface::MODAL); + } } //! From 21f28f5fd668da69fbc1e0a8daf8fca0cffdf5ee Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sun, 7 Apr 2024 21:26:31 -0400 Subject: [PATCH 57/62] Change CheckBlockIndexJob to initialization call This will cause the wallet to ShowChainCorruptedMessage() and either delete the blockchain files (in the GUI case) and end, or post a log entry with instructions and end. A missing pprev on any blockindex entry is fatal and the wallet should not be allowed to continue operation without rebuilding the chain data. --- src/gridcoin/gridcoin.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/gridcoin/gridcoin.cpp b/src/gridcoin/gridcoin.cpp index b9292896d5..acb79106f3 100644 --- a/src/gridcoin/gridcoin.cpp +++ b/src/gridcoin/gridcoin.cpp @@ -374,20 +374,23 @@ void InitializeExplorerFeatures() //! whether the index contains invalid state caused by an unclean shutdown. //! This condition was originally detected by an assertion in a routine for //! stake modifier checksum verification. Because Gridcoin removed modifier -//! checksums and checkpoints, we reinstate that assertion here as a formal -//! inspection. +//! checksums, we reinstate that assertion here as a formal inspection done +//! at initialization before the VerifyCheckpoints. //! //! This function checks that no block index entries contain a null pointer //! to a previous block. The symptom may indicate a deeper problem that can //! be resolved by tuning disk synchronization in LevelDB. Until then, this //! heuristic has proven itself to be effective for identifying a corrupted -//! database. +//! database. This type of error has not been seen in the wild in several +//! years as of Gridcoin 5.4.7.0, but is retained for thoroughness. //! -void CheckBlockIndexJob() +bool CheckBlockIndex() { LogPrintf("Gridcoin: checking block index..."); + uiInterface.InitMessage(_("Checking block index...")); - bool corrupted = false; + // Block index integrity status + bool status = true; if (pindexGenesisBlock) { LOCK(cs_main); @@ -396,18 +399,20 @@ void CheckBlockIndexJob() const CBlockIndex* const pindex = index_pair.second; if (!pindex || !(pindex->pprev || pindex == pindexGenesisBlock)) { - corrupted = true; + status = false; break; } } } - if (!corrupted) { + if (status) { LogPrintf("Gridcoin: block index is clean"); - return; + return status; } ShowChainCorruptedMessage(); + + return status; } //! @@ -503,6 +508,9 @@ bool GRC::Initialize(ThreadHandlerPtr threads, CBlockIndex* pindexBest) { LogPrintf("Gridcoin: initializing..."); + if (!CheckBlockIndex()) { + return false; + } if (!VerifyCheckpoints(pindexBest)) { return false; } @@ -531,8 +539,6 @@ void GRC::CloseResearcherRegistryFile() void GRC::ScheduleBackgroundJobs(CScheduler& scheduler) { - scheduler.schedule(CheckBlockIndexJob, std::chrono::system_clock::now()); - // Primitive, but this is what the scraper does in the scraper housekeeping // loop. It checks to see if the logs need to be archived by default every // 5 mins. Note that passing false to the archive function means that if we From 8154056179c2bb81434f4c15c68ab3f8e44025a8 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sun, 7 Apr 2024 22:12:34 -0400 Subject: [PATCH 58/62] Change scheduled DB passivations to use RegistryBookmarks --- src/gridcoin/beacon.cpp | 15 --------------- src/gridcoin/beacon.h | 7 +------ src/gridcoin/contract/handler.h | 15 +++++++++++++++ src/gridcoin/gridcoin.cpp | 17 ++++++++++++----- src/gridcoin/gridcoin.h | 6 ++++++ src/gridcoin/project.cpp | 15 --------------- src/gridcoin/project.h | 9 ++------- src/gridcoin/protocol.cpp | 15 --------------- src/gridcoin/protocol.h | 7 +------ src/gridcoin/scraper/scraper_registry.cpp | 15 --------------- src/gridcoin/scraper/scraper_registry.h | 7 +------ src/gridcoin/sidestake.cpp | 15 --------------- src/gridcoin/sidestake.h | 7 +------ 13 files changed, 39 insertions(+), 111 deletions(-) diff --git a/src/gridcoin/beacon.cpp b/src/gridcoin/beacon.cpp index e529fdff07..3fdcfc9e61 100644 --- a/src/gridcoin/beacon.cpp +++ b/src/gridcoin/beacon.cpp @@ -1391,21 +1391,6 @@ BeaconRegistry::BeaconDB &BeaconRegistry::GetBeaconDB() return m_beacon_db; } -// This is static and called by the scheduler. -void BeaconRegistry::RunDBPassivation() -{ - TRY_LOCK(cs_main, locked_main); - - if (!locked_main) - { - return; - } - - BeaconRegistry& beacons = GetBeaconRegistry(); - - beacons.PassivateDB(); -} - template<> const std::string BeaconRegistry::BeaconDB::KeyType() { return std::string("beacon"); diff --git a/src/gridcoin/beacon.h b/src/gridcoin/beacon.h index 64970d7bac..e97d1fd0f3 100644 --- a/src/gridcoin/beacon.h +++ b/src/gridcoin/beacon.h @@ -768,7 +768,7 @@ class BeaconRegistry : public IContractHandler //! //! \return The number of elements passivated. //! - uint64_t PassivateDB(); + uint64_t PassivateDB() override; //! //! \brief This function walks the linked beacon entries back (using the m_previous_hash member) from a provided @@ -795,11 +795,6 @@ class BeaconRegistry : public IContractHandler //! bool SetNeedsIsContractCorrection(bool flag); - //! - //! \brief A static function that is called by the scheduler to run the beacon database passivation. - //! - static void RunDBPassivation(); - //! //! \brief Specializes the template RegistryDB for the ScraperEntry class //! diff --git a/src/gridcoin/contract/handler.h b/src/gridcoin/contract/handler.h index 9d2d462d5a..5bb121e1bf 100644 --- a/src/gridcoin/contract/handler.h +++ b/src/gridcoin/contract/handler.h @@ -5,6 +5,7 @@ #ifndef GRIDCOIN_CONTRACT_HANDLER_H #define GRIDCOIN_CONTRACT_HANDLER_H +#include #include class CBlockIndex; @@ -153,6 +154,20 @@ struct IContractHandler //! \param height //! virtual void SetDBHeight(int& height); + + //! + //! \brief Passivates the elements in the underlying db, which means remove from memory elements in the + //! historical map that are not referenced by any of the in memory maps. The backing store of + //! the element removed from memory is retained and will be transparently restored if find() + //! is called on the hash key for the element. + //! + //! \return The number of elements passivated. + //! + virtual uint64_t PassivateDB() + { + // The default method here does nothing. + return uint64_t {0}; + }; }; } // namespace GRC diff --git a/src/gridcoin/gridcoin.cpp b/src/gridcoin/gridcoin.cpp index acb79106f3..693eb318fd 100644 --- a/src/gridcoin/gridcoin.cpp +++ b/src/gridcoin/gridcoin.cpp @@ -484,11 +484,8 @@ void ScheduleRegistriesPassivation(CScheduler& scheduler) { // Run registry database passivation every 5 minutes. This is a very thin call most of the time. // Please see the PassivateDB function and passivate_db. - // TODO: Turn into a loop using extension of RegistryBookmarks - scheduler.scheduleEvery(BeaconRegistry::RunDBPassivation, std::chrono::minutes{5}); - scheduler.scheduleEvery(ScraperRegistry::RunDBPassivation, std::chrono::minutes{5}); - scheduler.scheduleEvery(ProtocolRegistry::RunDBPassivation, std::chrono::minutes{5}); - scheduler.scheduleEvery(Whitelist::RunDBPassivation, std::chrono::minutes{5}); + + scheduler.scheduleEvery(RunDBPassivation, std::chrono::minutes{5}); } } // Anonymous namespace @@ -608,3 +605,13 @@ skip:; return true; } +void GRC::RunDBPassivation() +{ + LOCK(cs_main); + + for (const auto& contract_type : RegistryBookmarks::CONTRACT_TYPES_WITH_REG_DB) { + Registry& registry = RegistryBookmarks::GetRegistryWithDB(contract_type); + + registry.PassivateDB(); + } +} diff --git a/src/gridcoin/gridcoin.h b/src/gridcoin/gridcoin.h index dbd6bde049..d9c17e21bf 100644 --- a/src/gridcoin/gridcoin.h +++ b/src/gridcoin/gridcoin.h @@ -40,6 +40,12 @@ void ScheduleBackgroundJobs(CScheduler& scheduler); //! \return \c true if no errors occurred. //! bool CleanConfig(); + +//! +//! \brief Function to allow cycling through DB passivation for all contract types backed +//! with registry db. +//! +void RunDBPassivation(); } // namespace GRC #endif // GRIDCOIN_GRIDCOIN_H diff --git a/src/gridcoin/project.cpp b/src/gridcoin/project.cpp index 6db6511067..cf5c805e18 100644 --- a/src/gridcoin/project.cpp +++ b/src/gridcoin/project.cpp @@ -541,21 +541,6 @@ Whitelist::ProjectEntryDB &Whitelist::GetProjectDB() return m_project_db; } -// This is static and called by the scheduler. -void Whitelist::RunDBPassivation() -{ - TRY_LOCK(cs_main, locked_main); - - if (!locked_main) - { - return; - } - - Whitelist& project_entries = GetWhitelist(); - - project_entries.PassivateDB(); -} - template<> const std::string Whitelist::ProjectEntryDB::KeyType() { return std::string("project"); diff --git a/src/gridcoin/project.h b/src/gridcoin/project.h index 5b6ff5fae2..9e4c55ae87 100644 --- a/src/gridcoin/project.h +++ b/src/gridcoin/project.h @@ -603,19 +603,14 @@ class Whitelist : public IContractHandler void ResetInMemoryOnly(); //! - //! \brief Passivates the elements in the scraper db, which means remove from memory elements in the + //! \brief Passivates the elements in the project db, which means remove from memory elements in the //! historical map that are not referenced by m_projects. The backing store of the element removed //! from memory is retained and will be transparently restored if find() is called on the hash key //! for the element. //! //! \return The number of elements passivated. //! - uint64_t PassivateDB(); - - //! - //! \brief A static function that is called by the scheduler to run the project entry database passivation. - //! - static void RunDBPassivation(); + uint64_t PassivateDB() override; //! //! \brief Specializes the template RegistryDB for the ScraperEntry class. Note that std::set is not diff --git a/src/gridcoin/protocol.cpp b/src/gridcoin/protocol.cpp index ec5f0831e9..bd32a6838d 100644 --- a/src/gridcoin/protocol.cpp +++ b/src/gridcoin/protocol.cpp @@ -528,21 +528,6 @@ ProtocolRegistry::ProtocolEntryDB &ProtocolRegistry::GetProtocolEntryDB() return m_protocol_db; } -// This is static and called by the scheduler. -void ProtocolRegistry::RunDBPassivation() -{ - TRY_LOCK(cs_main, locked_main); - - if (!locked_main) - { - return; - } - - ProtocolRegistry& protocol_entries = GetProtocolRegistry(); - - protocol_entries.PassivateDB(); -} - template<> const std::string ProtocolRegistry::ProtocolEntryDB::KeyType() { return std::string("protocol"); diff --git a/src/gridcoin/protocol.h b/src/gridcoin/protocol.h index 37aa39bc53..3e8f400e17 100644 --- a/src/gridcoin/protocol.h +++ b/src/gridcoin/protocol.h @@ -559,12 +559,7 @@ class ProtocolRegistry : public IContractHandler //! //! \return The number of elements passivated. //! - uint64_t PassivateDB(); - - //! - //! \brief A static function that is called by the scheduler to run the protocol entry database passivation. - //! - static void RunDBPassivation(); + uint64_t PassivateDB() override; //! //! \brief Specializes the template RegistryDB for the ProtocolEntry class. Note that std::set diff --git a/src/gridcoin/scraper/scraper_registry.cpp b/src/gridcoin/scraper/scraper_registry.cpp index bf481e0216..5a22fb11ad 100644 --- a/src/gridcoin/scraper/scraper_registry.cpp +++ b/src/gridcoin/scraper/scraper_registry.cpp @@ -573,21 +573,6 @@ ScraperRegistry::ScraperEntryDB &ScraperRegistry::GetScraperDB() return m_scraper_db; } -// This is static and called by the scheduler. -void ScraperRegistry::RunDBPassivation() -{ - TRY_LOCK(cs_main, locked_main); - - if (!locked_main) - { - return; - } - - ScraperRegistry& scraper_entries = GetScraperRegistry(); - - scraper_entries.PassivateDB(); -} - template<> const std::string ScraperRegistry::ScraperEntryDB::KeyType() { return std::string("scraper"); diff --git a/src/gridcoin/scraper/scraper_registry.h b/src/gridcoin/scraper/scraper_registry.h index 5686c25991..8256b7e11b 100644 --- a/src/gridcoin/scraper/scraper_registry.h +++ b/src/gridcoin/scraper/scraper_registry.h @@ -598,12 +598,7 @@ class ScraperRegistry : public IContractHandler //! //! \return The number of elements passivated. //! - uint64_t PassivateDB(); - - //! - //! \brief A static function that is called by the scheduler to run the scraper entry database passivation. - //! - static void RunDBPassivation(); + uint64_t PassivateDB() override; //! //! \brief Specializes the template RegistryDB for the ScraperEntry class. Note that std::set is diff --git a/src/gridcoin/sidestake.cpp b/src/gridcoin/sidestake.cpp index 2c9e53966d..0c553d6eef 100644 --- a/src/gridcoin/sidestake.cpp +++ b/src/gridcoin/sidestake.cpp @@ -1164,21 +1164,6 @@ SideStakeRegistry::SideStakeDB &SideStakeRegistry::GetSideStakeDB() return m_sidestake_db; } -// This is static and called by the scheduler. -void SideStakeRegistry::RunDBPassivation() -{ - TRY_LOCK(cs_main, locked_main); - - if (!locked_main) - { - return; - } - - SideStakeRegistry& SideStake_entries = GetSideStakeRegistry(); - - SideStake_entries.PassivateDB(); -} - template<> const std::string SideStakeRegistry::SideStakeDB::KeyType() { return std::string("SideStake"); diff --git a/src/gridcoin/sidestake.h b/src/gridcoin/sidestake.h index 2737085e6c..d909e7f27a 100644 --- a/src/gridcoin/sidestake.h +++ b/src/gridcoin/sidestake.h @@ -830,7 +830,7 @@ class SideStakeRegistry : public IContractHandler //! //! \return The number of elements passivated. //! - uint64_t PassivateDB(); + uint64_t PassivateDB() override; //! //! \brief This method parses the config file for local sidestakes. It is based on the original GetSideStakingStatusAndAlloc() @@ -838,11 +838,6 @@ class SideStakeRegistry : public IContractHandler //! void LoadLocalSideStakesFromConfig(); - //! - //! \brief A static function that is called by the scheduler to run the sidestake entry database passivation. - //! - static void RunDBPassivation(); - //! //! \brief Specializes the template RegistryDB for the SideStake class. Note that std::set //! is not actually used. From ddf33f624df11b7211e203d67dbb63cbda71144f Mon Sep 17 00:00:00 2001 From: div72 Date: Mon, 8 Apr 2024 20:11:39 +0300 Subject: [PATCH 59/62] staking: add a missing check --- src/gridcoin/staking/kernel.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gridcoin/staking/kernel.cpp b/src/gridcoin/staking/kernel.cpp index 7f1952140d..ccb154862e 100644 --- a/src/gridcoin/staking/kernel.cpp +++ b/src/gridcoin/staking/kernel.cpp @@ -603,21 +603,21 @@ bool GRC::CheckProofOfStakeV8( CTransaction txPrev; if (!ReadStakedInput(txdb, prevout.hash, header, txPrev, pindexPrev)) - return tx.DoS(1, error("%s: read staked input failed", __func__)); + return tx.DoS(10, error("%s: read staked input failed", __func__)); if (!VerifySignature(txPrev, tx, 0, 0)) return tx.DoS(100, error("%s: VerifySignature failed on coinstake %s", __func__, tx.GetHash().ToString())); // Check times if (tx.nTime < txPrev.nTime) - return error("%s: nTime violation", __func__); + return tx.DoS(100, error("%s: nTime violation", __func__)); if (header.nTime + nStakeMinAge > tx.nTime) - return error("%s: min age violation", __func__); + return tx.DoS(100, error("%s: min age violation", __func__)); if (Block.nVersion >= 12) { if (tx.nTime != MaskStakeTime(tx.nTime)) { - return error("%s: mask violation", __func__); + return tx.DoS(100, error("%s: mask violation", __func__)); } } @@ -649,5 +649,9 @@ bool GRC::CheckProofOfStakeV8( ); // Now check if proof-of-stake hash meets target protocol - return bnHashProof <= bnTarget; + if (bnHashProof > bnTarget) { + return tx.DoS(100, error("%s: invalid proof (proof: %s, target: %s)", __func__, bnHashProof.GetHex(), bnTarget.GetHex())); + } + + return true; } From b3a4d1de091aefe2f5f21cdc68da558ec3b2ac3a Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Mon, 8 Apr 2024 15:43:37 -0400 Subject: [PATCH 60/62] Increment version to 5.4.7.2. --- CMakeLists.txt | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b78ffddbfb..de0d3e765d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ HunterGate( # ===================== project("Gridcoin" - VERSION 5.4.7.1 + VERSION 5.4.7.2 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" LANGUAGES C CXX diff --git a/configure.ac b/configure.ac index 57f433e582..c8701b8996 100755 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 4) define(_CLIENT_VERSION_REVISION, 7) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_IS_RELEASE, false) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) From cec9c89978854fd7f9a2168c1f91e275826ee3e9 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 10 Apr 2024 17:55:10 -0400 Subject: [PATCH 61/62] Update CHANGELOG for 5.4.8.0 leisure release. --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f194b20dad..216af62361 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/). +## [5.4.8.0], 2024-04-10, leisure + +### Added + - build: add option for sanitizers #2553 (@div72) + - build: CMake: Initial Windows support (MSYS2) #2733 (@CyberTailor) + +### Changed + - build: enforce SSE2 on x86 targets #2746 (@div72) + - consensus: Update checkpoint data for mainnet and testnet #2756 (@jamescowens) + - gui, util: Enhance verify checkpoints fail handling; use RegistryBookmarks for DB passivation #2758 (@jamescowens) + +### Removed + +### Fixed + - build, depends: fix compilation with XCode 15 #2747 (@div72) + - Fix man page installation path for cmake builds #2749 (@theMarix) + - consensus, mrc, sidestake: add mrc fees to staker to rewards to be allocated via sidestaking #2753 (@jamescowens) + - Fix Systemd unit install location #2754 (@theMarix) + - scraper: Corrections to scraper_net after removal of cntPartsRcvd decrement and increment #2755 (@jamescowens) + - rpc: fix setban segfault #2757 (@div72) + ## [5.4.7.0], 2024-03-13, leisure ### Added From 0029870dde7e4f085a22cf3455ea4e554d34a0a7 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 10 Apr 2024 17:56:52 -0400 Subject: [PATCH 62/62] Update version to 5.4.8.0 for leisure release. --- CMakeLists.txt | 4 ++-- configure.ac | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de0d3e765d..95398687fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,13 +28,13 @@ HunterGate( # ===================== project("Gridcoin" - VERSION 5.4.7.2 + VERSION 5.4.8.0 DESCRIPTION "POS-based cryptocurrency that rewards BOINC computation" HOMEPAGE_URL "https://gridcoin.us" LANGUAGES C CXX ) -set(CLIENT_VERSION_IS_RELEASE "false") +set(CLIENT_VERSION_IS_RELEASE "true") set(COPYRIGHT_YEAR "2024") set(COPYRIGHT_HOLDERS_FINAL "The Gridcoin developers") diff --git a/configure.ac b/configure.ac index c8701b8996..f2ff757821 100755 --- a/configure.ac +++ b/configure.ac @@ -2,9 +2,9 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 4) -define(_CLIENT_VERSION_REVISION, 7) -define(_CLIENT_VERSION_BUILD, 2) -define(_CLIENT_VERSION_IS_RELEASE, false) +define(_CLIENT_VERSION_REVISION, 8) +define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Gridcoin]])