Fix null pointer crashes causing seed node crash-loops (v5.8.1)

Guard pindexBest and pprev dereferences that segfault during IBD
block serving when chain state is incomplete:
- kernel.cpp: CheckStakeKernelHash null pindexBest during PoS validation
- main.cpp: InvalidChainFound null pprev/pindexBest on rejected blocks
- main.cpp: SetBestChain null pprev in trust calculation
- main.cpp: ProcessBlock orphan handler null pindexBest

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-17 00:55:48 -07:00
parent a0e8e74d0d
commit cd7b68f7cb
4 changed files with 18 additions and 12 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ if(POLICY CMP0167)
endif() endif()
project(Triangles project(Triangles
VERSION 5.8.0.0 VERSION 5.8.1.0
DESCRIPTION "Cryptographic Triangles Wallet" DESCRIPTION "Cryptographic Triangles Wallet"
LANGUAGES C CXX LANGUAGES C CXX
) )
+1 -1
View File
@@ -8,7 +8,7 @@
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it // These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 5 #define CLIENT_VERSION_MAJOR 5
#define CLIENT_VERSION_MINOR 8 #define CLIENT_VERSION_MINOR 8
#define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_REVISION 1
#define CLIENT_VERSION_BUILD 0 #define CLIENT_VERSION_BUILD 0
// Converts the parameter X to a string after macro replacement on X has been performed. // Converts the parameter X to a string after macro replacement on X has been performed.
+6 -4
View File
@@ -334,9 +334,11 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
// Now check if proof-of-stake hash meets target protocol // Now check if proof-of-stake hash meets target protocol
if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay) if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
{ {
// Guard against null pindexBest during early startup / IBD
int nCurrentHeight = pindexBest ? pindexBest->nHeight : 0;
// triangles fix: accept hash to get blockchain moving again with Pharao release (v 4.0.0.1) for first 10 blocks after release // triangles fix: accept hash to get blockchain moving again with Pharao release (v 4.0.0.1) for first 10 blocks after release
//printf(">>>> pindexBest->nHeight %d\n",pindexBest->nHeight); if (nCurrentHeight > CRAPCHAIN_CUTOFF_BLOCK)
if (pindexBest->nHeight > CRAPCHAIN_CUTOFF_BLOCK)
{ {
if(fDebug) if(fDebug)
{ {
@@ -349,8 +351,8 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
else else
{ {
//accept hash //accept hash
if (pindexBest->nHeight % 10000 == 0 || pindexBest->nHeight > 2186900) if (nCurrentHeight % 10000 == 0 || nCurrentHeight > 2186900)
printf(">>>> pindexBest->nHeight %d, Pharao release - hash accepted\n", pindexBest->nHeight); printf(">>>> pindexBest->nHeight %d, Pharao release - hash accepted\n", nCurrentHeight);
} }
} }
+10 -6
View File
@@ -1504,8 +1504,12 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
uiInterface.NotifyBlocksChanged(); uiInterface.NotifyBlocksChanged();
} }
uint256 nBestInvalidBlockTrust = pindexNew->nChainTrust - pindexNew->pprev->nChainTrust; uint256 nBestInvalidBlockTrust = pindexNew->pprev
uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust; ? pindexNew->nChainTrust - pindexNew->pprev->nChainTrust
: pindexNew->nChainTrust;
uint256 nBestBlockTrust = (pindexBest && pindexBest->nHeight != 0 && pindexBest->pprev)
? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust)
: (pindexBest ? pindexBest->nChainTrust : uint256(0));
printf("InvalidChainFound: invalid block=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n", printf("InvalidChainFound: invalid block=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n",
pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight,
@@ -1513,9 +1517,9 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
DateTimeStrFormat("%x %H:%M:%S", pindexNew->GetBlockTime()).c_str()); DateTimeStrFormat("%x %H:%M:%S", pindexNew->GetBlockTime()).c_str());
printf("InvalidChainFound: current best=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n", printf("InvalidChainFound: current best=%s height=%d trust=%s blocktrust=%" PRId64 " date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
CBigNum(pindexBest->nChainTrust).ToString().c_str(), pindexBest ? CBigNum(pindexBest->nChainTrust).ToString().c_str() : "0",
nBestBlockTrust.Get64(), nBestBlockTrust.Get64(),
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); pindexBest ? DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str() : "unknown");
} }
@@ -2536,7 +2540,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
nTimeBestReceived = GetTime(); nTimeBestReceived = GetTime();
nTransactionsUpdated++; nTransactionsUpdated++;
uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust; uint256 nBestBlockTrust = (pindexBest->nHeight != 0 && pindexBest->pprev) ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
// Log every 5000 blocks during sync, every block once caught up // Log every 5000 blocks during sync, every block once caught up
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload()) if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
@@ -3165,7 +3169,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
} }
// Ask this guy to fill in what we're missing // Ask this guy to fill in what we're missing
if (pfrom) if (pfrom && pindexBest)
{ {
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
// triangles: getblocks may not obtain the ancestor block rejected // triangles: getblocks may not obtain the ancestor block rejected