From f0cb958cac3ee04cf71bdf83a5d3e5a34e06ae77 Mon Sep 17 00:00:00 2001 From: DanS Date: Thu, 12 Mar 2026 01:25:21 -0500 Subject: [PATCH] Fix fresh sync failure at diff reset height 2838976 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fresh-syncing nodes rejected the on-chain min-diff block at the RANDOMX_VALIDATION activation height (2838976) because GetNextWorkRequired computed the expected nBits from the preceding normal-difficulty blocks, producing 469847994 instead of the on-chain 0x200f0f0f (HUSH_MINDIFF_NBITS). This caused all seed nodes to be banned with "Incorrect diffbits" and the node could never sync past that height. Two changes: 1. GetNextWorkRequired (pow.cpp): Return nProofOfWorkLimit at the exact RANDOMX_VALIDATION activation height, matching the on-chain diff reset. 2. ContextualCheckBlockHeader (main.cpp): Raise DragonX daaForkHeight to RANDOMX_VALIDATION + 62000, covering the window where nBits was never validated (diff reset at 2838976 through the attack at ~2879907). Tested by invalidating block 2838975 and reconsidering — node re-validated through the diff reset and attack window, syncing back to tip with zero bad-diffbits rejections. Bump version to 1.0.1. --- build.sh | 2 +- configure.ac | 2 +- src/clientversion.h | 2 +- src/main.cpp | 9 ++++++++- src/pow.cpp | 10 ++++++++++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 29fb86fd2..c4dc95dc6 100755 --- a/build.sh +++ b/build.sh @@ -6,7 +6,7 @@ set -eu -o pipefail -VERSION="1.0.0" +VERSION="1.0.1" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" RELEASE_DIR="$SCRIPT_DIR/release" diff --git a/configure.ac b/configure.ac index 7f6b47d9a..0654b5ea3 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) dnl Must be kept in sync with src/clientversion.h , ugh! define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 0) +define(_CLIENT_VERSION_REVISION, 1) define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) diff --git a/src/clientversion.h b/src/clientversion.h index 2df7a3ec6..ba12b7349 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -30,7 +30,7 @@ // Must be kept in sync with configure.ac , ugh! #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 0 +#define CLIENT_VERSION_REVISION 1 #define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build diff --git a/src/main.cpp b/src/main.cpp index a045afce3..d66af71c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5107,7 +5107,14 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta assert(pindexPrev); - int daaForkHeight = GetArg("-daaforkheight", 450000); + // For HUSH3, nBits validation starts above the original DAA fork height (450000). + // For DragonX, nBits was never validated before the standalone binary, so the + // chain contains blocks with incorrect nBits during the vulnerable window + // (diff reset at RANDOMX_VALIDATION height through the attack at ~2879907). + // Set daaForkHeight past that window so fresh sync accepts historical blocks. + bool isdragonx = strncmp(SMART_CHAIN_SYMBOL, "DRAGONX", 7) == 0; + int defaultDaaForkHeight = isdragonx ? ASSETCHAINS_RANDOMX_VALIDATION + 62000 : 450000; + int daaForkHeight = GetArg("-daaforkheight", defaultDaaForkHeight); int nHeight = pindexPrev->GetHeight()+1; bool ishush3 = strncmp(SMART_CHAIN_SYMBOL, "HUSH3",5) == 0 ? true : false; // Check Proof-of-Work difficulty diff --git a/src/pow.cpp b/src/pow.cpp index 309a0831a..6bcbc1ca4 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -315,6 +315,16 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead if (pindexLast == NULL ) return nProofOfWorkLimit; + // DragonX difficulty reset at the RANDOMX_VALIDATION activation height. + // The chain transitioned to a new binary at this height and difficulty was + // reset to minimum (powLimit). Without this, fresh-syncing nodes compute + // a different nBits from GetNextWorkRequired (based on pre-reset blocks) + // and reject the on-chain min-diff block, banning all seed nodes. + if (ASSETCHAINS_RANDOMX_VALIDATION > 0 && pindexLast->GetHeight() + 1 == ASSETCHAINS_RANDOMX_VALIDATION) { + LogPrintf("%s: difficulty reset to powLimit at height %d\n", __func__, ASSETCHAINS_RANDOMX_VALIDATION); + return nProofOfWorkLimit; + } + //{ // Comparing to pindexLast->nHeight with >= because this function // returns the work required for the block after pindexLast.