-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Fix some chainstate-init-order bugs. #10758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix some chainstate-init-order bugs. #10758
Conversation
61d0d7f
to
7bfd19d
Compare
Note that the two generic "Error initializing block database" strings really should be changed, but as we are already in string freeze for 0.15, they will have to stay as-is for now :(. |
bcd6bb9
to
5925964
Compare
5925964
to
8d5f2c3
Compare
More explicitly fixed the bug that I accidentally fixed by being more explicit - RewindBlockIndex MUST be called even if we start with -reindex-chainstate. |
This needs an 0.15 tag as it fixes some bugs. |
8d5f2c3
to
db8d863
Compare
Rebased and added a fix for the issue @sipa pointed out at #10770 (comment) |
src/validation.cpp
Outdated
} | ||
|
||
if (needs_init) { | ||
// Note that LoadBlockIndexDB may have set fReindex if we shut down |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have difficulty parsing this sentence. Can you split it up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, rewrote the comment.
@TheBlueMatt When starting with |
db8d863
to
c93db42
Compare
ACK @TheBlueMatt I retract my comment, everything seems to be working like before. |
I'd like to see this in 0.15 as it at least turns an assert into an error message, in case your chainstate is out of sync with the block chain. |
This (or some subset of it) absolutely has to land for 15, it fixes several regressions currently on master, but its a bugfix, so doesn't need to land today (but isnt small, so should go sooner rather than later). |
I haven't finished reviewing, but this also fixes a crash when using an invalid -wallet argument. For example: |
utACK c93db42 Strongly advocate for merging this in the near term. |
In current master running
With this branch gives
Reporting this here because of c93db42. |
@sipa hmm, re: restarting-mid-reindex: your original comment that it was broken was more correct than your later retraction. Fixed and cleaned that stuff up more with more comments :). |
@TheBlueMatt if it's not related with your refactor then IMO a new PR would be best. |
921e3ae
to
c93db42
Compare
OK, removed the top two commits so this is just what it was that got ACKs. The two commits from the top are in #10919, which should likely also be taken for 15. |
reutACK c93db429f909e75fbeacd2419fb8434350e3b674 |
src/validation.cpp
Outdated
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus())) | ||
return error("LoadBlockIndex(): genesis block not accepted"); | ||
} catch (const std::runtime_error& e) { | ||
return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error is no longer correct, this is "failed to load genesis block" now I guess?
src/validation.cpp
Outdated
CDiskBlockPos blockPos; | ||
CValidationState state; | ||
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) | ||
return error("LoadBlockIndex(): FindBlockPos failed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to use error("%s: ...", __func__)
here as in other places, but in any case, the function name is wrong now.
utACK apart from error message nits |
* Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start.
This gives LoadChainTip a return value - allowing it to indicate that the UTXO DB ran ahead of the block DB. This just provides a nicer error message instead of the previous mysterious assert(!setBlockIndexCandidates.empty()) error. This also calls ActivateBestChain in case we just loaded the genesis block in LoadChainTip, avoiding relying on the ActivateBestChain in ThreadImport before continuing init process.
RewindBlockIndex works over both chainActive - disconnecting blocks from the tip that need witness verification - and mapBlockIndex - requiring redownload of blocks missing witness data. It should never have been the case that the second half is skipped if we're about to run -reindex-chainstate.
* Order chainstate init more logically - first all of the blocktree-related loading, then coinsdb, then pcoinsTip/chainActive. Only create objects as needed. * More clearly document exactly what is and isn't called in -reindex and -reindex-chainstate both with comments noting calls as no-ops and by adding if guards. * Move LoadGenesisBlock further down in init. This is a more logical location for it, as it is after all of the blockindex-related loading and checking, but before any of the UTXO-related loading and checking. * Move all of the VerifyDB()-related stuff into a -reindex + -reindex-chainstate if guard. It couldn't do anything useful as chainActive.Tip() would be null at this point anyway.
This was introduced by 3192975. It can be triggered easily when canceling DB upgrade from pre-per-utxo.
c93db42
to
c0025d0
Compare
Fixed error printings in LoadGenesisBlock. |
re-utACK c0025d0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK, left some nits.
Is it worth backporting the RewindBlockIndex bugfix to the 0.13 or 0.14 branch? I could imagine someone upgrading from 0.13.0 to the latest 0.13 release after segwit activates. Or to the latest 0.14 if the 0.15.0 release comes out after activation?
@@ -72,7 +72,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha | |||
pblocktree = new CBlockTreeDB(1 << 20, true); | |||
pcoinsdbview = new CCoinsViewDB(1 << 23, true); | |||
pcoinsTip = new CCoinsViewCache(pcoinsdbview); | |||
if (!InitBlockIndex(chainparams)) { | |||
if (!LoadGenesisBlock(chainparams)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The string on the next line ought to be changed to reflect the new function name.
} catch (const std::runtime_error& e) { | ||
return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); | ||
} | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment at line 3900 now seems outdated; perhaps it makes more sense to move it to init.cpp:1422
?
// mapBlockIndex. Note that we can't use chainActive here, since it is | ||
// set based on the coins db, not the block index db, which is the only | ||
// thing loaded at this point. | ||
if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: curly braces for this if
|
||
// Load pointer to end of best chain | ||
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); | ||
if (it == mapBlockIndex.end()) | ||
return; | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: perhaps add the curly braces here, while you're at it
@@ -1437,10 +1427,34 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) | |||
break; | |||
} | |||
|
|||
// At this point blocktree args are consistent with what's on disk. | |||
// If we're not mid-reindex (based on disk + args), add a genesis block on disk. | |||
// This is called again in ThreadImport in the reindex completes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"in the reindex completes" -> "after the reindex completes"?
I'm going to merge this now - sorry @sdaftuar, we should fix your minor nits later, but we have to make some progress with merging for 0.15 |
c0025d0 Fix segfault when shutting down before fully loading (Matt Corallo) 1385697 Order chainstate init more logically. (Matt Corallo) ff3a219 Call RewindBlockIndex even if we're about to run -reindex-chainstate (Matt Corallo) b0f3249 More user-friendly error message if UTXO DB runs ahead of block DB (Matt Corallo) eda888e Fix some LoadChainTip-related init-order bugs. (Matt Corallo) Pull request description: This does a number of things to clean up chainstate init order, fixing some issues as it goes: * Order chainstate init more logically - first all of the blocktree-related loading, then coinsdb, then pcoinsTip/chainActive. Only create objects as needed. * More clearly document exactly what is and isn't called in -reindex and -reindex-chainstate both with comments noting calls as no-ops and by adding if guards. * Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start. * Move LoadGenesisBlock further down in init. This is a more logical location for it, as it is after all of the blockindex-related loading and checking, but before any of the UTXO-related loading and checking. * Give LoadChainTip a return value - allowing it to indicate that the UTXO DB ran ahead of the block DB. This just provides a nicer error message instead of the previous mysterious assert(!setBlockIndexCandidates.empty()) error. * Calls ActivateBestChain in case we just loaded the genesis block in LoadChainTip, avoiding relying on the ActivateBestChain in ThreadImport before continuing init process. * Move all of the VerifyDB()-related stuff into a -reindex + -reindex-chainstate if guard. It couldn't do anything useful as chainActive.Tip() would be null at this point anyway. Tree-SHA512: 3c96ee7ed44f4130bee3479a40c5cd99a619fda5e309c26d60b54feab9f6ec60fabab8cf47a049c9cf15e88999b2edb7f16cbe6819e97273560b201a89d90762
@laanwj Agreed, I don't think those nits should have held this up. |
e7539f8 Fix some broken init-time prints/constants (Matt Corallo) 13ab353 Check for empty coinsview instead of just-reset coinsview in init (Matt Corallo) fce3f4f Fix resume-of-reindex-after-restart (Matt Corallo) efac91e Always wait for threadGroup to exit in bitcoind shutdown (Matt Corallo) Pull request description: This is a follow-on to #10758 to help move 10758 along. The first fixes a regression in master that was partially fixed in 10758, the second I'm not sure if its a regression or not, but its clearly a bug that should be fixed. Tree-SHA512: aca7b97a97dca66e1a218a33cc6f4aa002292ff1bb0af64e35b81fbaa91b9504f2605375808b43e93a63fc73634ad079b30ef6c9f4ba338d3b5f72d816dfeaff
c0025d0 Fix segfault when shutting down before fully loading (Matt Corallo) 1385697 Order chainstate init more logically. (Matt Corallo) ff3a219 Call RewindBlockIndex even if we're about to run -reindex-chainstate (Matt Corallo) b0f3249 More user-friendly error message if UTXO DB runs ahead of block DB (Matt Corallo) eda888e Fix some LoadChainTip-related init-order bugs. (Matt Corallo) Pull request description: This does a number of things to clean up chainstate init order, fixing some issues as it goes: * Order chainstate init more logically - first all of the blocktree-related loading, then coinsdb, then pcoinsTip/chainActive. Only create objects as needed. * More clearly document exactly what is and isn't called in -reindex and -reindex-chainstate both with comments noting calls as no-ops and by adding if guards. * Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start. * Move LoadGenesisBlock further down in init. This is a more logical location for it, as it is after all of the blockindex-related loading and checking, but before any of the UTXO-related loading and checking. * Give LoadChainTip a return value - allowing it to indicate that the UTXO DB ran ahead of the block DB. This just provides a nicer error message instead of the previous mysterious assert(!setBlockIndexCandidates.empty()) error. * Calls ActivateBestChain in case we just loaded the genesis block in LoadChainTip, avoiding relying on the ActivateBestChain in ThreadImport before continuing init process. * Move all of the VerifyDB()-related stuff into a -reindex + -reindex-chainstate if guard. It couldn't do anything useful as chainActive.Tip() would be null at this point anyway. Tree-SHA512: 3c96ee7ed44f4130bee3479a40c5cd99a619fda5e309c26d60b54feab9f6ec60fabab8cf47a049c9cf15e88999b2edb7f16cbe6819e97273560b201a89d90762
c0025d0 Fix segfault when shutting down before fully loading (Matt Corallo) 1385697 Order chainstate init more logically. (Matt Corallo) ff3a219 Call RewindBlockIndex even if we're about to run -reindex-chainstate (Matt Corallo) b0f3249 More user-friendly error message if UTXO DB runs ahead of block DB (Matt Corallo) eda888e Fix some LoadChainTip-related init-order bugs. (Matt Corallo) Pull request description: This does a number of things to clean up chainstate init order, fixing some issues as it goes: * Order chainstate init more logically - first all of the blocktree-related loading, then coinsdb, then pcoinsTip/chainActive. Only create objects as needed. * More clearly document exactly what is and isn't called in -reindex and -reindex-chainstate both with comments noting calls as no-ops and by adding if guards. * Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start. * Move LoadGenesisBlock further down in init. This is a more logical location for it, as it is after all of the blockindex-related loading and checking, but before any of the UTXO-related loading and checking. * Give LoadChainTip a return value - allowing it to indicate that the UTXO DB ran ahead of the block DB. This just provides a nicer error message instead of the previous mysterious assert(!setBlockIndexCandidates.empty()) error. * Calls ActivateBestChain in case we just loaded the genesis block in LoadChainTip, avoiding relying on the ActivateBestChain in ThreadImport before continuing init process. * Move all of the VerifyDB()-related stuff into a -reindex + -reindex-chainstate if guard. It couldn't do anything useful as chainActive.Tip() would be null at this point anyway. Tree-SHA512: 3c96ee7ed44f4130bee3479a40c5cd99a619fda5e309c26d60b54feab9f6ec60fabab8cf47a049c9cf15e88999b2edb7f16cbe6819e97273560b201a89d90762
e7539f8 Fix some broken init-time prints/constants (Matt Corallo) 13ab353 Check for empty coinsview instead of just-reset coinsview in init (Matt Corallo) fce3f4f Fix resume-of-reindex-after-restart (Matt Corallo) efac91e Always wait for threadGroup to exit in bitcoind shutdown (Matt Corallo) Pull request description: This is a follow-on to bitcoin#10758 to help move 10758 along. The first fixes a regression in master that was partially fixed in 10758, the second I'm not sure if its a regression or not, but its clearly a bug that should be fixed. Tree-SHA512: aca7b97a97dca66e1a218a33cc6f4aa002292ff1bb0af64e35b81fbaa91b9504f2605375808b43e93a63fc73634ad079b30ef6c9f4ba338d3b5f72d816dfeaff
e7539f8 Fix some broken init-time prints/constants (Matt Corallo) 13ab353 Check for empty coinsview instead of just-reset coinsview in init (Matt Corallo) fce3f4f Fix resume-of-reindex-after-restart (Matt Corallo) efac91e Always wait for threadGroup to exit in bitcoind shutdown (Matt Corallo) Pull request description: This is a follow-on to bitcoin#10758 to help move 10758 along. The first fixes a regression in master that was partially fixed in 10758, the second I'm not sure if its a regression or not, but its clearly a bug that should be fixed. Tree-SHA512: aca7b97a97dca66e1a218a33cc6f4aa002292ff1bb0af64e35b81fbaa91b9504f2605375808b43e93a63fc73634ad079b30ef6c9f4ba338d3b5f72d816dfeaff
e7539f8 Fix some broken init-time prints/constants (Matt Corallo) 13ab353 Check for empty coinsview instead of just-reset coinsview in init (Matt Corallo) fce3f4f Fix resume-of-reindex-after-restart (Matt Corallo) efac91e Always wait for threadGroup to exit in bitcoind shutdown (Matt Corallo) Pull request description: This is a follow-on to bitcoin#10758 to help move 10758 along. The first fixes a regression in master that was partially fixed in 10758, the second I'm not sure if its a regression or not, but its clearly a bug that should be fixed. Tree-SHA512: aca7b97a97dca66e1a218a33cc6f4aa002292ff1bb0af64e35b81fbaa91b9504f2605375808b43e93a63fc73634ad079b30ef6c9f4ba338d3b5f72d816dfeaff
c0025d0 Fix segfault when shutting down before fully loading (Matt Corallo) 1385697 Order chainstate init more logically. (Matt Corallo) ff3a219 Call RewindBlockIndex even if we're about to run -reindex-chainstate (Matt Corallo) b0f3249 More user-friendly error message if UTXO DB runs ahead of block DB (Matt Corallo) eda888e Fix some LoadChainTip-related init-order bugs. (Matt Corallo) Pull request description: This does a number of things to clean up chainstate init order, fixing some issues as it goes: * Order chainstate init more logically - first all of the blocktree-related loading, then coinsdb, then pcoinsTip/chainActive. Only create objects as needed. * More clearly document exactly what is and isn't called in -reindex and -reindex-chainstate both with comments noting calls as no-ops and by adding if guards. * Move the writing of fTxIndex to LoadBlockIndex - this fixes a bug introduced in d6af06d where InitBlockIndex was writing to fTxIndex which had not yet been checked (because LoadChainTip hadn't yet initialized the chainActive, which would otherwise have resulted in InitBlockIndex being a NOP), allowing you to modify -txindex without reindex, potentially corrupting your chainstate! * Rename InitBlockIndex to LoadGenesisBlock, which is now a more natural name for it. Also check mapBlockIndex instead of chainActive, fixing a bug where we'd write the genesis block out on every start. * Move LoadGenesisBlock further down in init. This is a more logical location for it, as it is after all of the blockindex-related loading and checking, but before any of the UTXO-related loading and checking. * Give LoadChainTip a return value - allowing it to indicate that the UTXO DB ran ahead of the block DB. This just provides a nicer error message instead of the previous mysterious assert(!setBlockIndexCandidates.empty()) error. * Calls ActivateBestChain in case we just loaded the genesis block in LoadChainTip, avoiding relying on the ActivateBestChain in ThreadImport before continuing init process. * Move all of the VerifyDB()-related stuff into a -reindex + -reindex-chainstate if guard. It couldn't do anything useful as chainActive.Tip() would be null at this point anyway. Tree-SHA512: 3c96ee7ed44f4130bee3479a40c5cd99a619fda5e309c26d60b54feab9f6ec60fabab8cf47a049c9cf15e88999b2edb7f16cbe6819e97273560b201a89d90762
e7539f8 Fix some broken init-time prints/constants (Matt Corallo) 13ab353 Check for empty coinsview instead of just-reset coinsview in init (Matt Corallo) fce3f4f Fix resume-of-reindex-after-restart (Matt Corallo) efac91e Always wait for threadGroup to exit in bitcoind shutdown (Matt Corallo) Pull request description: This is a follow-on to bitcoin#10758 to help move 10758 along. The first fixes a regression in master that was partially fixed in 10758, the second I'm not sure if its a regression or not, but its clearly a bug that should be fixed. Tree-SHA512: aca7b97a97dca66e1a218a33cc6f4aa002292ff1bb0af64e35b81fbaa91b9504f2605375808b43e93a63fc73634ad079b30ef6c9f4ba338d3b5f72d816dfeaff
4749d52 [Refactoring][BUG] Unchecked LoadGenesisBlock return value (random-zebra) 43cc880 Fix segfault when shutting down before fully loading (Matt Corallo) 5f1f014 Order chainstate init more logically. (random-zebra) 9b87537 More user-friendly error message if UTXO DB runs ahead of block DB (Matt Corallo) 9bcc942 Fix some LoadChainTip-related init-order bugs. (random-zebra) Pull request description: Had this segfault when trying to shut down the wallet before the coins cache is loaded. ``` CCoinsViewCache::DynamicMemoryUsage (this=0x0) at coins.cpp:60 60 return memusage::DynamicUsage(cacheCoins) + (gdb) bt #0 0x0000555555bb8b44 in CCoinsViewCache::DynamicMemoryUsage() const (this=0x0) at coins.cpp:60 #1 0x0000555555996bc1 in FlushStateToDisk(CValidationState&, FlushStateMode) (state=..., mode=mode@entry=FLUSH_STATE_ALWAYS) at validation.cpp:1730 #2 0x0000555555997540 in FlushStateToDisk() () at validation.cpp:1806 #3 0x000055555582516c in PrepareShutdown() () at init.cpp:266 #4 0x0000555555826005 in Shutdown() () at init.cpp:339 ``` This is due to a bug introduced in 64c525b (we should null-check `pcoinsTip` before calling `FlushStateToDisk` at line 266, same as we do at line 283). Upstream fixed it in bitcoin#10758 among few other things. Backported here without ff3a219 (as we don't have `RewindBlockIndex` or `reindex-chainstate` yet). ACKs for top commit: Fuzzbawls: ACK 4749d52 furszy: ACK 4749d52 and merging.. Tree-SHA512: 23f27c4a9422a72794054698313259f89ad22a58dba2809901653e08c964c73e4eaeab872ada42380e76eb46ddd7e57f08b65f22812c791d0c2b274e5f0202a7
This does a number of things to clean up chainstate init order,
fixing some issues as it goes:
Order chainstate init more logically - first all of the
blocktree-related loading, then coinsdb, then
pcoinsTip/chainActive. Only create objects as needed.
More clearly document exactly what is and isn't called in
-reindex and -reindex-chainstate both with comments noting
calls as no-ops and by adding if guards.
Move the writing of fTxIndex to LoadBlockIndex - this fixes a
bug introduced in d6af06d where
InitBlockIndex was writing to fTxIndex which had not yet been
checked (because LoadChainTip hadn't yet initialized the
chainActive, which would otherwise have resulted in
InitBlockIndex being a NOP), allowing you to modify -txindex
without reindex, potentially corrupting your chainstate!
Rename InitBlockIndex to LoadGenesisBlock, which is now a more
natural name for it. Also check mapBlockIndex instead of
chainActive, fixing a bug where we'd write the genesis block out
on every start.
Move LoadGenesisBlock further down in init. This is a more logical
location for it, as it is after all of the blockindex-related
loading and checking, but before any of the UTXO-related loading
and checking.
Give LoadChainTip a return value - allowing it to indicate that
the UTXO DB ran ahead of the block DB. This just provides a nicer
error message instead of the previous mysterious
assert(!setBlockIndexCandidates.empty()) error.
Calls ActivateBestChain in case we just loaded the genesis
block in LoadChainTip, avoiding relying on the ActivateBestChain
in ThreadImport before continuing init process.
Move all of the VerifyDB()-related stuff into a -reindex +
-reindex-chainstate if guard. It couldn't do anything useful
as chainActive.Tip() would be null at this point anyway.