2021-09-20 16:12:18 -04:00
// Copyright (c) 2021 The Bitcoin Core developers
// 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-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>
# 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>
# 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>
# include <memory>
# include <vector>
2021-11-12 10:06:00 -05:00
namespace node {
2021-12-01 18:16:29 -05:00
ChainstateLoadResult LoadChainstate ( ChainstateManager & chainman , const CacheSizes & cache_sizes ,
const ChainstateLoadOptions & options )
2021-08-17 18:07:14 -04: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-09-20 16:12:18 -04:00
} ;
2022-08-29 12:11:22 +02:00
if ( ! hashAssumeValid . IsNull ( ) ) {
LogPrintf ( " Assuming ancestors of block %s have valid signatures. \n " , hashAssumeValid . GetHex ( ) ) ;
} else {
LogPrintf ( " Validating signatures for all blocks. \n " ) ;
}
LogPrintf ( " Setting nMinimumChainWork=%s \n " , nMinimumChainWork . GetHex ( ) ) ;
if ( nMinimumChainWork < UintToArith256 ( chainman . GetConsensus ( ) . nMinimumChainWork ) ) {
LogPrintf ( " Warning: nMinimumChainWork set below default value of %s \n " , chainman . GetConsensus ( ) . nMinimumChainWork . GetHex ( ) ) ;
}
2022-09-01 17:22:27 +02:00
if ( nPruneTarget = = std : : numeric_limits < uint64_t > : : max ( ) ) {
LogPrintf ( " Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files. \n " ) ;
} else if ( nPruneTarget ) {
LogPrintf ( " Prune configured to target %u MiB on disk for block and undo files. \n " , nPruneTarget / 1024 / 1024 ) ;
}
2022-08-29 12:11:22 +02:00
2021-12-07 12:06:03 -05:00
LOCK ( cs_main ) ;
2021-12-01 18:16:29 -05:00
chainman . InitializeChainstate ( options . mempool ) ;
chainman . m_total_coinstip_cache = cache_sizes . coins ;
chainman . m_total_coinsdb_cache = cache_sizes . coins_db ;
2021-12-07 12:06:03 -05:00
auto & pblocktree { chainman . m_blockman . m_block_tree_db } ;
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree . reset ( ) ;
2021-12-01 18:16:29 -05:00
pblocktree . reset ( new CBlockTreeDB ( cache_sizes . block_tree_db , options . block_tree_db_in_memory , options . reindex ) ) ;
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 ) {
2021-12-07 12:06:03 -05:00
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
2021-12-01 18:16:29 -05:00
if ( options . check_interrupt & & options . check_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 ( ) ) {
2021-12-01 18:16:29 -05:00
if ( options . check_interrupt & & options . check_interrupt ( ) ) return { ChainstateLoadStatus : : INTERRUPTED , { } } ;
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).
// This is called again in ThreadImport after the reindex completes.
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
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 ( ) ) {
2021-12-07 12:06:03 -05:00
chainstate - > InitCoinsDB (
2021-12-01 18:16:29 -05:00
/*cache_size_bytes=*/ cache_sizes . coins_db ,
/*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
2021-12-01 18:16:29 -05:00
chainstate - > InitCoinsCache ( cache_sizes . coins ) ;
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
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : SUCCESS , { } } ;
2021-11-10 15:57:14 -05:00
}
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
}
if ( ! CVerifyDB ( ) . VerifyDB (
2022-05-18 18:49:36 +02:00
* chainstate , chainman . GetConsensus ( ) , chainstate - > CoinsDB ( ) ,
2021-12-01 18:16:29 -05:00
options . check_level ,
options . check_blocks ) ) {
2021-12-01 18:16:29 -05:00
return { ChainstateLoadStatus : : FAILURE , _ ( " Corrupted block database detected " ) } ;
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