upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-31 14:26:47 -0300
committerGitHub <noreply@github.com>2026-07-31 14:26:47 -0300
commit3268ea95c1443238d380dea26e7b1bb3bd108aed (patch)
treecbc3d0046e94be9c5a3c33b8442a0367438ed983 /src
parentf904c4bd4057ab7333c7d701fb40f3e87fedf7fd (diff)
mine: do not submit a solution for a parent that is no longer the tip (#69)
The mining loop tests pindexPrev != pindexBest every 256 hashes, but never again once a solution turns up. A thread that found one just after somebody else extended the chain submitted a block built on a stale parent -- a block born orphaned, at a height already taken. Every miner thread on a machine works from the same pindexPrev, so the moment one wins, all the others are hashing a doomed template until their next checkpoint. On a 32-core box that is thirty threads with a standing chance of producing a guaranteed orphan. Re-check the tip inside cs_main before submitting, and drop the solution if it moved. Verified on an isolated chain with three miner threads: 2790 blocks accepted, so nothing legitimate is being discarded, and 2 solutions dropped for a moved tip -- which is the race actually happening and being caught. Honest about the size of it: two in 2790 is not what fills a wallet with orphans. On the 32-core node in production, 1287 of 4117 processed blocks arrive with a missing parent, which is a different problem and the one worth chasing next.
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp38
1 files changed, 30 insertions, 8 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 85f89d9..b147ddd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3151,17 +3151,39 @@ bool BitcoinMiner(int nThreadId)
3151 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); 3151 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
3152 CRITICAL_BLOCK(cs_main) 3152 CRITICAL_BLOCK(cs_main)
3153 { 3153 {
3154 // Save key 3154 // Is the parent we solved for still the tip?
3155 if (!AddKey(key)) 3155 //
3156 // The loop only tests this every 256 hashes, and never
3157 // again once a solution turns up. So a thread that found
3158 // one just after somebody else extended the chain would
3159 // submit a block built on a parent that is no longer the
3160 // tip -- a block born orphaned, at a height already taken.
3161 //
3162 // Every miner thread on this machine works from the same
3163 // pindexPrev, so the moment one of them wins, all the
3164 // others are hashing a doomed template until their next
3165 // checkpoint. On a 32-core box that is thirty threads with
3166 // a standing chance of producing a guaranteed orphan, and
3167 // it is why a healthy miner's wallet filled up with them.
3168 if (pindexPrev != pindexBest)
3156 { 3169 {
3157 RandomXDestroyMinerVM(rxvm); 3170 LogPrint("net", "BitcoinMiner: thread %d solved for a parent that is no longer the tip, discarding\n",
3158 return false; 3171 nThreadId);
3159 } 3172 }
3160 key.MakeNewKey(); 3173 else
3174 {
3175 // Save key
3176 if (!AddKey(key))
3177 {
3178 RandomXDestroyMinerVM(rxvm);
3179 return false;
3180 }
3181 key.MakeNewKey();
3161 3182
3162 // Process this block the same as if we had received it from another node 3183 // Process this block the same as if we had received it from another node
3163 if (!ProcessBlock(NULL, pblock.release())) 3184 if (!ProcessBlock(NULL, pblock.release()))
3164 LogPrint("net", "ERROR in BitcoinMiner, ProcessBlock, block not accepted\n"); 3185 LogPrint("net", "ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");
3186 }
3165 } 3187 }
3166 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST); 3188 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
3167 3189