From 69710af200a0254262c92ddfb96f8bbf4fb6636d Mon Sep 17 00:00:00 2001 From: div72 Date: Sat, 2 Mar 2024 12:14:54 +0300 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 493b739a5d435d8c242fc422eef033ac2e85379c Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 6 Mar 2024 15:51:26 -0500 Subject: [PATCH 06/10] 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 6f230bae40e6daf68456b44d1133214090a5b14e Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Tue, 12 Mar 2024 17:02:12 -0400 Subject: [PATCH 07/10] Ban nodes 5.4.5.0 and below --- src/main.cpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8aa9e05018..f20773b226 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2049,11 +2049,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Note the std::max is there to deal with the rollover of BlockV12Height + DISCONNECT_GRACE_PERIOD if // BlockV12Height is set to std::numeric_limits::max() which is the case during testing. if (pfrom->nVersion < MIN_PEER_PROTO_VERSION - || (DISCONNECT_OLD_VERSION_AFTER_GRACE_PERIOD - && pfrom->nVersion < PROTOCOL_VERSION - && pindexBest->nHeight > std::max(Params().GetConsensus().BlockV12Height, - Params().GetConsensus().BlockV12Height + DISCONNECT_GRACE_PERIOD))) - { + || (DISCONNECT_OLD_VERSION_AFTER_GRACE_PERIOD + && pfrom->nVersion < PROTOCOL_VERSION + && pindexBest->nHeight > std::max(Params().GetConsensus().BlockV12Height, + Params().GetConsensus().BlockV12Height + DISCONNECT_GRACE_PERIOD) + ) + ) { // disconnect from peers older than this proto version LogPrint(BCLog::LogFlags::NOISY, "partner %s using obsolete version %i; disconnecting", pfrom->addr.ToString(), pfrom->nVersion); @@ -2064,8 +2065,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; - if (!vRecv.empty()) + + if (!vRecv.empty()) { vRecv >> pfrom->strSubVer; + + // This handles the special disconnect for clients between the mandatory 5.4.0.0 and the 5.4.5.0 since + // 5.4.6.0 effectively became a mandatory due to the contract version error in TxMessage. The protocol version + // was not incremented since 5.4.6.0 was originally a leisure and so this is the only reasonable way to distinguish + // in this situation. + if (pfrom->strSubVer.find("5.4.5") != std::string::npos + || pfrom->strSubVer.find("5.4.4") != std::string::npos + || pfrom->strSubVer.find("5.4.3") != std::string::npos + || pfrom->strSubVer.find("5.4.2") != std::string::npos + || pfrom->strSubVer.find("5.4.1") != std::string::npos + || pfrom->strSubVer.find("5.4.0") != std::string::npos + ) { + + pfrom->fDisconnect = true; + return false; + } + } + if (!vRecv.empty()) vRecv >> pfrom->nStartingHeight; From 9c9f280f2bb07bcef82aacb731ba31858211342d Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Tue, 12 Mar 2024 23:11:21 -0400 Subject: [PATCH 08/10] Increment version to 5.4.7.0 for release. --- CMakeLists.txt | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09cc834388..0836128949 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.18) project("Gridcoin" - VERSION 5.4.6.0 + VERSION 5.4.7.0 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 db4d895adc..fa97189dad 100755 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ 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, 6) +define(_CLIENT_VERSION_REVISION, 7) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) From a84055bcbaa87a944cac158671f721a6ce38fe6e Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Tue, 12 Mar 2024 23:40:56 -0400 Subject: [PATCH 09/10] Update CHANGELOG for 5.4.7.0 release. --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 945a0ecc15..f194b20dad 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ 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.7.0], 2024-03-13, leisure + +### Added + - net, consensus: Ban nodes 5.4.5.0 and below #2751 (@jamescowens) + +### Changed + +### Removed + +### Fixed + - util: Adjust Fraction class addition overload overflow tests #2748 (@jamescowens) + ## [5.4.6.0], 2024-03-02, leisure, "Miss Piggy" ### Added From a16718ff8da16bdb4985655999694900dafefe2f Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 13 Mar 2024 15:40:57 -0400 Subject: [PATCH 10/10] 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]])