diff -uNr a/bitcoin/manifest b/bitcoin/manifest --- a/bitcoin/manifest 8a72565420e5da35289c60885864984d1b4421f81148b625ddf72c9ea16718c4cbd47d1b6821fe468123f4597fdac72024ea01cef839001a27db57373d3c2186 +++ b/bitcoin/manifest 5e95516c2bdccfbb9fdb2924c3e1f778472d30287367b604c954be289c309fde87e44a3367c27734df0e167d7fa36ae267bc6ed8d3c79625b7ca15bf97f1fa3f @@ -40,3 +40,4 @@ 707665 bitcoin_boost_prune_built_libs jfw Reduce precompiled Boost libraries to the four actually in use. 709104 bitcoin_tx_fee_cleanup jfw Add nMinRelayTxFee global accessed with new -minrelaytxfee option, minrelaytxfee field in getinfo, and setminrelaytxfee RPC command. Use this to replace the fixed MIN_RELAY_TX_FEE. Simplify mempool acceptance rules so this threshold always applies (no special-case free transactions or rubber-banding threshold by current block size). Adjust block generation logic accordingly, though it still sorts on a strange age-value priority rather than fee. Simplify wallet to always send using its configured fee (-paytxfee) and change its default to match the default minrelaytxfee, removing the fixed MIN_TX_FEE. Make nTransactionFee access thread-safe and expand the help text for its inconsistently named RPC setter. Fees are now figured properly without premature rounding, as floor((size*rate)/1024) rather than (floor(size/1000)+1)*rate. *NOTE:* This change may substantially impact wallet transaction fees and node memory usage patterns but puts more control over these in the hands of the operator. 712609 bitcoin_fsync_all_blocks jfw Don't skip fsync of blocks to disk during sync, because this can leave the raw block collection unrecoverably inconsistent with the BDB block index in the event of a crash. +713908 bitcoin_checkblocks_cleanup jfw Let the -checkblocks option take a positive integer value to set the the check depth limit or zero for no limit. Drop the default from 2500 to 144. Break the implementation out from a long-winded CTxDB member function whose class context was irrelevant to it. Simplify its loop bounds (which revealed a corner case of genesis block possibly going unchecked), fix off-by-one on the nominal depth limit and make it count from the first *good* block found. Add progress reporting and improve error messages and commentary. Exit before loading other things when it fails. *NOTE:* This breaks CLI/config file compatibility with the prior sloppy undocumented situation where any -checkblocks value at all would enable full checking. diff -uNr a/bitcoin/src/db.cpp b/bitcoin/src/db.cpp --- a/bitcoin/src/db.cpp 387ae498b8e968a7a3d7640e0b34f677b8cf60279928ba33d8054e26cf23f8d5e798cc857a81cc23433de5669808e4ce621e0b37649c06d86fbc29da2630539d +++ b/bitcoin/src/db.cpp 9bf77e52f028a37eebaf701d3602ebf04c2e1f57cbd358a898f89e160b3da2c7d71d1f5386cbb03520d2e7471857644dd3e5bccd24bf47f3a08657360c3e2a42 @@ -18,6 +18,7 @@ unsigned int nWalletDBUpdated; uint64 nAccountingEntryNumber = 0; +static bool CheckDiskBlocks(); // @@ -583,28 +584,50 @@ // Load bnBestInvalidWork, OK if it doesn't exist ReadBestInvalidWork(bnBestInvalidWork); + return CheckDiskBlocks(); +} + +static bool CheckDiskBlocks() +{ // Verify blocks in the best chain CBlockIndex* pindexFork = NULL; - for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) + int counter = 0; + for (CBlockIndex* pindex = pindexBest; pindex; pindex = pindex->pprev) { - if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks")) + // Depth limiter given by -checkblocks=. 0 means to check all; negative values aren't allowed but if we see one anyway then treat it as 0. + if (nCheckBlocks > 0 && pindex->nHeight <= nBestHeight-nCheckBlocks) break; + + if (!counter) + { + // Log progress at start and periodically. + printf(" CheckDiskBlocks() at height=%d ...\n", pindex->nHeight); + counter = 1000; + } + --counter; + CBlock block; if (!block.ReadFromDisk(pindex)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); + // Either OS-level read failure, or proof-of-work didn't match the header's claimed difficulty (probably corrupt data leading to bad hash). + return error("CheckDiskBlocks() : block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!block.CheckBlock()) { - printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + printf("CheckDiskBlocks() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; + if (!pindexFork) + return error("CheckDiskBlocks() : failed to load any good blocks including genesis!"); + nBestHeight = pindexFork->nHeight; // Update this right away for the purposes of the depth limiter to be sure we've actually reached a good chain. } } if (pindexFork) { // Reorg back to the fork - printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); + // XXX need to clarify how this can happen and justify how it's sufficient to recover. (E.g., given that apparently we leave the bad blocks on disk and their headers in the RAM index and blkindex database - would that prevent us from receiving a corrected version of a faulty block, thinking we already had it?) + printf("CheckDiskBlocks() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); CBlock block; if (!block.ReadFromDisk(pindexFork)) - return error("LoadBlockIndex() : block.ReadFromDisk failed"); + return error("CheckDiskBlocks() : block.ReadFromDisk failed (this shouldn't happen: the same block was successfully checked earlier!)"); CTxDB txdb; block.SetBestChain(txdb, pindexFork); } diff -uNr a/bitcoin/src/init.cpp b/bitcoin/src/init.cpp --- a/bitcoin/src/init.cpp 60e5cc7e8afa70278b7c37eb9ec1d53e161e79b7809f908aef4bda8d448b455176f3902460e79ccad2f99aa80b1fd34002adc1dda51f2acca6c29a5e7a8b1fda +++ b/bitcoin/src/init.cpp 65d10b2fb7d554c0833d97931fde3429dad8a61d1c8e5a9c3d590d67340c43356a35a3ebcce1f4a96eee9e13b1b359a2173814cc97bccdfe6fd6a7d94ea0f74a @@ -191,6 +191,7 @@ " -keypool= \t " + _("Set key pool size to (default: 100)\n") + " -rescan Rescan the block chain for missing wallet transactions\n" + " -disablesafemode Don't lock certain commands when hazards are detected such as DB corruption or network fork\n" + + " -checkblocks= Check the last blocks in current chain on disk for inconsistencies at startup; 0 to check entire current chain (default: 144)\n" + " -? This help message\n"; // Remove tabs @@ -246,6 +247,17 @@ SetMinRelayTxFee(nMinFee); } + if (mapArgs.count("-checkblocks")) + { + int64 tmp = atoi64(mapArgs["-checkblocks"]); + if (tmp < 0 || tmp >= INT_MAX) + { + fprintf(stderr, "-checkblocks= value out of range\n"); + return false; + } + nCheckBlocks = tmp; + } + for (int i = 1; i < argc; i++) if (!IsSwitchChar(argv[i][0])) fCommandLine = true; @@ -318,11 +330,13 @@ strErrors += _("Error loading addr.dat \n"); printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); - InitMessage(_("Loading block index...")); printf("Loading block index...\n"); nStart = GetTimeMillis(); if (!LoadBlockIndex()) - strErrors += _("Error loading blkindex.dat \n"); + { + fprintf(stderr, "Error loading block index\n"); + return false; // We'd better not proceed to touching the wallet if the block index is bad. + } printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); InitMessage(_("Loading wallet...")); diff -uNr a/bitcoin/src/main.cpp b/bitcoin/src/main.cpp --- a/bitcoin/src/main.cpp c2f38d7e3e2772ee004f8b212eb71c872f09e7e9aa8f7e3c84b11e1c5f0860310a95c3ae0d0ea24b56f6e728c38b3421bdd404e6c6547440d4520b17f2b2a57d +++ b/bitcoin/src/main.cpp 1d1d30ea6ea4bb23d6f24216f94f7cb47e7575995adb8b833bbb95b082bbedda90983be2ad3a28be4b8fa6dffb0926e906a596b90044c64145c6cc4dd0900eb9 @@ -55,6 +55,7 @@ int nLimitProcessors = 1; int fMinimizeToTray = true; int fMinimizeOnClose = true; +int nCheckBlocks = 144; static int64 nTransactionFee = 10000; static int64 nMinRelayTxFee = 10000; static CCriticalSection cs_settings; diff -uNr a/bitcoin/src/main.h b/bitcoin/src/main.h --- a/bitcoin/src/main.h 593317b93b1ca134595672039e5abb0b0dd23efa85d5a7eb170b078fde135c96413bbe8b40cc308c3796dc5a83456903592f3e966d07475e2336c3e6887a6f4f +++ b/bitcoin/src/main.h e1aa413b33f7ec0c3943aae831a5a2fc3795360707d44a31ebb5f810300d8b17ca1dbfd5ddc7785f02366f857694d0eb2746aa27efdd2d40b220387d2baa88ca @@ -65,6 +65,7 @@ extern int nLimitProcessors; extern int fMinimizeToTray; extern int fMinimizeOnClose; +extern int nCheckBlocks; int64 GetTransactionFee(); void SetTransactionFee(int64 nFee);