2022-12-24 23:49:50 +00:00
// Copyright (c) 2021-2022 The Bitcoin Core developers
2021-09-20 16:12:18 -04:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include <node/chainstate.h>
2022-09-10 14:09:48 +02:00
# include <arith_uint256.h>
2022-07-19 14:05:01 +02:00
# include <chain.h>
# include <coins.h>
2021-11-11 14:40:50 -05:00
# include <consensus/params.h>
2022-09-10 14:09:48 +02:00
# include <logging.h>
2021-11-11 14:40:50 -05:00
# include <node/blockstorage.h>
2021-12-01 18:16:29 -05:00
# include <node/caches.h>
2022-07-19 14:05:01 +02:00
# include <sync.h>
# include <threadsafety.h>
2022-07-21 20:16:03 +02:00
# include <tinyformat.h>
2022-07-19 14:05:01 +02:00
# include <txdb.h>
# include <uint256.h>
2023-03-15 11:18:06 +01:00
# include <util/fs.h>
2023-07-07 17:32:54 -04:00
# include <util/signalinterrupt.h>
2022-07-19 14:05:01 +02:00
# include <util/time.h>
2022-07-21 20:16:03 +02:00
# include <util/translation.h>
2021-11-11 14:40:50 -05:00
# include <validation.h>
2021-09-20 16:12:18 -04:00
2022-07-19 14:05:01 +02:00
# include <algorithm>
# include <atomic>
# include <cassert>
2022-09-10 14:09:48 +02:00
# include <limits>
2022-07-19 14:05:01 +02:00
# include <memory>
# include <vector>
2021-11-12 10:06:00 -05:00
namespace node {
2022-11-03 14:37:24 -04:00
// Complete initialization of chainstates after the initial call has been made
// to ChainstateManager::InitializeChainstate().
static ChainstateLoadResult CompleteChainstateInitialization (
ChainstateManager & chainman ,
const CacheSizes & cache_sizes ,
const ChainstateLoadOptions & options ) EXCLUSIVE_LOCKS_REQUIRED ( : : cs_main )
2021-08-17 18:07:14 -04:00
{
2021-12-07 12:06:03 -05:00
auto & pblocktree { chainman . m_blockman . m_block_tree_db } ;
2023-08-02 07:50:22 +02:00
// new BlockTreeDB tries to delete the existing file, which
2021-12-07 12:06:03 -05:00
// fails if it's still open from the previous loop. Close it first:
pblocktree . reset ( ) ;
2023-08-02 07:50:22 +02:00
pblocktree = std : : make_unique < BlockTreeDB > ( DBParams {
2022-08-16 23:32:55 -04:00
. path = chainman . m_options . datadir / " blocks " / " index " ,
2022-08-16 23:32:55 -04:00
. cache_bytes = static_cast < size_t > ( cache_sizes . block_tree_db ) ,
. memory_only = options . block_tree_db_in_memory ,
. wipe_data = options . reindex ,
2022-08-16 23:32:55 -04:00
. options = chainman . m_options . block_tree_db } ) ;
2021-12-07 12:06:03 -05:00
2021-12-01 18:16:29 -05:00
if ( options . reindex ) {
2021-12-07 12:06:03 -05:00
pblocktree - > WriteReindexing ( true ) ;
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
2021-12-01 18:16:29 -05:00
if ( options . prune ) {
2023-02-18 15:49:41 +01:00
chainman . m_blockman . CleanupBlockRevFiles ( ) ;
2021-12-01 18:16:29 -05:00
}
2021-12-07 12:06:03 -05:00
}
2021-09-20 17:46:06 -04:00
2023-07-07 17:32:54 -04:00
if ( chainman . m_interrupt ) return { ChainstateLoadStatus : : INTERRUPTED , { } } ;
2021-09-20 16:12:18 -04:00
2022-03-18 12:35:52 -04:00
// LoadBlockIndex will load m_have_pruned if we've ever removed a
2021-12-07 12:06:03 -05:00
// block file from disk.
2021-12-01 18:16:29 -05:00
// Note that it also sets fReindex global based on the disk flag!
// From here on, fReindex and options.reindex values may be different!
2021-12-07 12:06:03 -05:00
if ( ! chainman . LoadBlockIndex ( ) ) {
2023-07-07 17:32:54 -04:00
if ( chainman . m_interrupt ) return { ChainstateLoadStatus : : INTERRUPTED , { } } ;
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Error loading block database " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 16:12:18 -04:00
2021-12-07 12:06:03 -05:00
if ( ! chainman . BlockIndex ( ) . empty ( ) & &
2022-05-18 18:49:36 +02:00
! chainman . m_blockman . LookupBlockIndex ( chainman . GetConsensus ( ) . hashGenesisBlock ) ) {
2021-12-01 18:16:29 -05:00
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
return { ChainstateLoadStatus : : FAILURE_INCOMPATIBLE_DB , _ ( " Incorrect or no genesis block found. Wrong datadir for network? " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 16:12:18 -04:00
2021-12-07 12:06:03 -05:00
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
2021-12-01 18:16:29 -05:00
if ( chainman . m_blockman . m_have_pruned & & ! options . prune ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 17:46:06 -04:00
2021-12-07 12:06:03 -05:00
// 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
// (otherwise we use the one already on disk).
2023-06-17 11:11:51 -03:00
// This is called again in ImportBlocks after the reindex completes.
2021-12-07 12:06:03 -05:00
if ( ! fReindex & & ! chainman . ActiveChainstate ( ) . LoadGenesisBlock ( ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Error initializing block database " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 16:12:18 -04:00
2022-11-03 14:37:24 -04:00
auto is_coinsview_empty = [ & ] ( Chainstate * chainstate ) EXCLUSIVE_LOCKS_REQUIRED ( : : cs_main ) {
return options . reindex | | options . reindex_chainstate | | chainstate - > CoinsTip ( ) . GetBestBlock ( ) . IsNull ( ) ;
} ;
2022-04-28 10:23:33 -04:00
assert ( chainman . m_total_coinstip_cache > 0 ) ;
assert ( chainman . m_total_coinsdb_cache > 0 ) ;
2022-04-20 17:40:01 -04:00
// Conservative value which is arbitrarily chosen, as it will ultimately be changed
// by a call to `chainman.MaybeRebalanceCaches()`. We just need to make sure
// that the sum of the two caches (40%) does not exceed the allowable amount
// during this temporary initialization state.
double init_cache_fraction = 0.2 ;
2021-12-07 12:06:03 -05:00
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
2021-09-20 17:46:06 -04:00
2022-03-09 12:37:19 -05:00
for ( Chainstate * chainstate : chainman . GetAll ( ) ) {
2022-04-20 17:40:01 -04:00
LogPrintf ( " Initializing chainstate %s \n " , chainstate - > ToString ( ) ) ;
2021-12-07 12:06:03 -05:00
chainstate - > InitCoinsDB (
2022-04-20 17:40:01 -04:00
/*cache_size_bytes=*/ chainman . m_total_coinsdb_cache * init_cache_fraction ,
2021-12-01 18:16:29 -05:00
/*in_memory=*/ options . coins_db_in_memory ,
/*should_wipe=*/ options . reindex | | options . reindex_chainstate ) ;
2021-09-20 17:46:06 -04:00
2021-12-01 18:16:29 -05:00
if ( options . coins_error_cb ) {
chainstate - > CoinsErrorCatcher ( ) . AddReadErrCallback ( options . coins_error_cb ) ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 17:46:06 -04:00
2022-02-02 13:23:02 +01:00
// Refuse to load unsupported database format.
2021-12-07 12:06:03 -05:00
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
2022-02-02 13:23:02 +01:00
if ( chainstate - > CoinsDB ( ) . NeedsUpgrade ( ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE_INCOMPATIBLE_DB , _ ( " Unsupported chainstate database format found. "
" Please restart with -reindex-chainstate. This will "
" rebuild the chainstate database. " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 16:12:18 -04:00
2021-12-07 12:06:03 -05:00
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if ( ! chainstate - > ReplayBlocks ( ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate. " ) } ;
2021-12-07 12:06:03 -05:00
}
2021-09-20 16:12:18 -04:00
2021-12-07 12:06:03 -05:00
// The on-disk coinsdb is now in a good state, create the cache
2022-04-20 17:40:01 -04:00
chainstate - > InitCoinsCache ( chainman . m_total_coinstip_cache * init_cache_fraction ) ;
2021-12-07 12:06:03 -05:00
assert ( chainstate - > CanFlushToDisk ( ) ) ;
2021-09-20 16:12:18 -04:00
2021-12-07 12:06:03 -05:00
if ( ! is_coinsview_empty ( chainstate ) ) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if ( ! chainstate - > LoadChainTip ( ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Error initializing block database " ) } ;
2021-09-20 17:46:06 -04:00
}
2021-12-07 12:06:03 -05:00
assert ( chainstate - > m_chain . Tip ( ) ! = nullptr ) ;
2021-09-20 17:46:06 -04:00
}
2021-12-07 12:06:03 -05:00
}
2021-09-20 17:46:06 -04:00
2021-12-01 18:16:29 -05:00
if ( ! options . reindex ) {
2021-12-07 12:06:03 -05:00
auto chainstates { chainman . GetAll ( ) } ;
if ( std : : any_of ( chainstates . begin ( ) , chainstates . end ( ) ,
2022-03-09 12:37:19 -05:00
[ ] ( const Chainstate * cs ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main ) { return cs - > NeedsRedownload ( ) ; } ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , strprintf ( _ ( " Witness data for blocks after height %d requires validation. Please restart with -reindex. " ) ,
chainman . GetConsensus ( ) . SegwitHeight ) } ;
} ;
2021-09-20 17:46:06 -04:00
}
2021-09-20 16:12:18 -04:00
2022-04-20 17:40:01 -04:00
// Now that chainstates are loaded and we're able to flush to
// disk, rebalance the coins caches to desired levels based
// on the condition of each chainstate.
chainman . MaybeRebalanceCaches ( ) ;
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : SUCCESS , { } } ;
2021-11-10 15:57:14 -05:00
}
2022-11-03 14:37:24 -04:00
ChainstateLoadResult LoadChainstate ( ChainstateManager & chainman , const CacheSizes & cache_sizes ,
const ChainstateLoadOptions & options )
{
if ( ! chainman . AssumedValidBlock ( ) . IsNull ( ) ) {
LogPrintf ( " Assuming ancestors of block %s have valid signatures. \n " , chainman . AssumedValidBlock ( ) . GetHex ( ) ) ;
} else {
LogPrintf ( " Validating signatures for all blocks. \n " ) ;
}
LogPrintf ( " Setting nMinimumChainWork=%s \n " , chainman . MinimumChainWork ( ) . GetHex ( ) ) ;
if ( chainman . MinimumChainWork ( ) < UintToArith256 ( chainman . GetConsensus ( ) . nMinimumChainWork ) ) {
LogPrintf ( " Warning: nMinimumChainWork set below default value of %s \n " , chainman . GetConsensus ( ) . nMinimumChainWork . GetHex ( ) ) ;
}
2023-03-15 16:10:24 +01:00
if ( chainman . m_blockman . GetPruneTarget ( ) = = BlockManager : : PRUNE_TARGET_MANUAL ) {
2022-11-03 14:37:24 -04:00
LogPrintf ( " Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files. \n " ) ;
} else if ( chainman . m_blockman . GetPruneTarget ( ) ) {
LogPrintf ( " Prune configured to target %u MiB on disk for block and undo files. \n " , chainman . m_blockman . GetPruneTarget ( ) / 1024 / 1024 ) ;
}
LOCK ( cs_main ) ;
chainman . m_total_coinstip_cache = cache_sizes . coins ;
chainman . m_total_coinsdb_cache = cache_sizes . coins_db ;
// Load the fully validated chainstate.
chainman . InitializeChainstate ( options . mempool ) ;
// Load a chain created from a UTXO snapshot, if any exist.
2023-10-03 00:18:53 +02:00
bool has_snapshot = chainman . DetectSnapshotChainstate ( ) ;
2023-05-03 15:39:51 -04:00
if ( has_snapshot & & ( options . reindex | | options . reindex_chainstate ) ) {
LogPrintf ( " [snapshot] deleting snapshot chainstate due to reindexing \n " ) ;
if ( ! chainman . DeleteSnapshotChainstate ( ) ) {
return { ChainstateLoadStatus : : FAILURE_FATAL , Untranslated ( " Couldn't remove snapshot chainstate. " ) } ;
}
}
2022-11-03 14:37:24 -04:00
auto [ init_status , init_error ] = CompleteChainstateInitialization ( chainman , cache_sizes , options ) ;
if ( init_status ! = ChainstateLoadStatus : : SUCCESS ) {
return { init_status , init_error } ;
}
2022-04-28 10:23:33 -04:00
// If a snapshot chainstate was fully validated by a background chainstate during
// the last run, detect it here and clean up the now-unneeded background
// chainstate.
//
// Why is this cleanup done here (on subsequent restart) and not just when the
// snapshot is actually validated? Because this entails unusual
// filesystem operations to move leveldb data directories around, and that seems
// too risky to do in the middle of normal runtime.
auto snapshot_completion = chainman . MaybeCompleteSnapshotValidation ( ) ;
if ( snapshot_completion = = SnapshotCompletionResult : : SKIPPED ) {
// do nothing; expected case
} else if ( snapshot_completion = = SnapshotCompletionResult : : SUCCESS ) {
LogPrintf ( " [snapshot] cleaning up unneeded background chainstate, then reinitializing \n " ) ;
if ( ! chainman . ValidatedSnapshotCleanup ( ) ) {
2023-06-12 11:48:27 -04:00
return { ChainstateLoadStatus : : FAILURE_FATAL , Untranslated ( " Background chainstate cleanup failed unexpectedly. " ) } ;
2022-04-28 10:23:33 -04:00
}
// Because ValidatedSnapshotCleanup() has torn down chainstates with
// ChainstateManager::ResetChainstates(), reinitialize them here without
// duplicating the blockindex work above.
assert ( chainman . GetAll ( ) . empty ( ) ) ;
assert ( ! chainman . IsSnapshotActive ( ) ) ;
assert ( ! chainman . IsSnapshotValidated ( ) ) ;
chainman . InitializeChainstate ( options . mempool ) ;
// A reload of the block index is required to recompute setBlockIndexCandidates
// for the fully validated chainstate.
2023-06-06 07:50:51 -04:00
chainman . ActiveChainstate ( ) . ClearBlockIndexCandidates ( ) ;
2022-04-28 10:23:33 -04:00
auto [ init_status , init_error ] = CompleteChainstateInitialization ( chainman , cache_sizes , options ) ;
if ( init_status ! = ChainstateLoadStatus : : SUCCESS ) {
return { init_status , init_error } ;
}
} else {
return { ChainstateLoadStatus : : FAILURE , _ (
" UTXO snapshot failed to validate. "
" Restart to resume normal initial block download, or try loading a different snapshot. " ) } ;
}
2022-11-03 14:37:24 -04:00
return { ChainstateLoadStatus : : SUCCESS , { } } ;
}
2021-12-01 18:16:29 -05:00
ChainstateLoadResult VerifyLoadedChainstate ( ChainstateManager & chainman , const ChainstateLoadOptions & options )
2021-11-10 15:57:14 -05:00
{
2022-03-09 12:37:19 -05:00
auto is_coinsview_empty = [ & ] ( Chainstate * chainstate ) EXCLUSIVE_LOCKS_REQUIRED ( : : cs_main ) {
2021-12-01 18:16:29 -05:00
return options . reindex | | options . reindex_chainstate | | chainstate - > CoinsTip ( ) . GetBestBlock ( ) . IsNull ( ) ;
2021-11-10 15:57:14 -05:00
} ;
2021-12-07 12:06:03 -05:00
LOCK ( cs_main ) ;
2022-03-09 12:37:19 -05:00
for ( Chainstate * chainstate : chainman . GetAll ( ) ) {
2021-12-07 12:06:03 -05:00
if ( ! is_coinsview_empty ( chainstate ) ) {
const CBlockIndex * tip = chainstate - > m_chain . Tip ( ) ;
2022-05-18 18:31:19 +02:00
if ( tip & & tip - > nTime > GetTime ( ) + MAX_FUTURE_BLOCK_TIME ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " The block database contains a block which appears to be from the future. "
" This may be due to your computer's date and time being set incorrectly. "
" Only rebuild the block database if you are sure that your computer's date and time are correct " ) } ;
2021-12-07 12:06:03 -05:00
}
2023-05-10 22:36:04 +02:00
VerifyDBResult result = CVerifyDB ( chainman . GetNotifications ( ) ) . VerifyDB (
2022-10-06 15:51:09 -04:00
* chainstate , chainman . GetConsensus ( ) , chainstate - > CoinsDB ( ) ,
options . check_level ,
options . check_blocks ) ;
switch ( result ) {
case VerifyDBResult : : SUCCESS :
2023-02-06 15:05:33 -05:00
case VerifyDBResult : : SKIPPED_MISSING_BLOCKS :
2022-10-06 15:51:09 -04:00
break ;
2023-02-24 14:09:27 -05:00
case VerifyDBResult : : INTERRUPTED :
return { ChainstateLoadStatus : : INTERRUPTED , _ ( " Block verification was interrupted " ) } ;
2022-10-06 15:51:09 -04:00
case VerifyDBResult : : CORRUPTED_BLOCK_DB :
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Corrupted block database detected " ) } ;
2022-10-06 17:11:02 -04:00
case VerifyDBResult : : SKIPPED_L3_CHECKS :
if ( options . require_full_verification ) {
return { ChainstateLoadStatus : : FAILURE_INSUFFICIENT_DBCACHE , _ ( " Insufficient dbcache for block verification " ) } ;
}
break ;
2022-10-06 15:51:09 -04:00
} // no default case, so the compiler can warn about missing cases
2021-09-20 16:12:18 -04:00
}
2021-09-20 17:46:06 -04:00
}
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : SUCCESS , { } } ;
2021-09-20 16:12:18 -04:00
}
2021-11-12 10:06:00 -05:00
} // namespace node