diff options
| author | Bitflash <btf01@proton.me> | 2026-07-31 14:26:47 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-31 14:26:47 -0300 |
| commit | 3268ea95c1443238d380dea26e7b1bb3bd108aed (patch) | |
| tree | cbc3d0046e94be9c5a3c33b8442a0367438ed983 /src | |
| parent | f904c4bd4057ab7333c7d701fb40f3e87fedf7fd (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.cpp | 38 |
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 | ||