Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 494 Lines • ▼ Show 20 Lines | private: | ||||
const size_t m_limit_ancestor_size; | const size_t m_limit_ancestor_size; | ||||
// These may be modified while evaluating a transaction (eg to account for | // These may be modified while evaluating a transaction (eg to account for | ||||
// in-mempool conflicts; see below). | // in-mempool conflicts; see below). | ||||
size_t m_limit_descendants; | size_t m_limit_descendants; | ||||
size_t m_limit_descendant_size; | size_t m_limit_descendant_size; | ||||
}; | }; | ||||
bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws) { | bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws) { | ||||
AssertLockHeld(cs_main); | |||||
AssertLockHeld(m_pool.cs); | |||||
const CTransactionRef &ptx = ws.m_ptx; | const CTransactionRef &ptx = ws.m_ptx; | ||||
const CTransaction &tx = *ws.m_ptx; | const CTransaction &tx = *ws.m_ptx; | ||||
const TxId &txid = ws.m_ptx->GetId(); | const TxId &txid = ws.m_ptx->GetId(); | ||||
// Copy/alias what we need out of args | // Copy/alias what we need out of args | ||||
const int64_t nAcceptTime = args.m_accept_time; | const int64_t nAcceptTime = args.m_accept_time; | ||||
const bool bypass_limits = args.m_bypass_limits; | const bool bypass_limits = args.m_bypass_limits; | ||||
std::vector<COutPoint> &coins_to_uncache = args.m_coins_to_uncache; | std::vector<COutPoint> &coins_to_uncache = args.m_coins_to_uncache; | ||||
▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | if (!m_pool.CheckPackageLimits(txns, m_limit_ancestors, | ||||
// error. | // error. | ||||
return package_state.Invalid(PackageValidationResult::PCKG_POLICY, | return package_state.Invalid(PackageValidationResult::PCKG_POLICY, | ||||
"package-mempool-limits", err_string); | "package-mempool-limits", err_string); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws) { | bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws) { | ||||
AssertLockHeld(cs_main); | |||||
AssertLockHeld(m_pool.cs); | |||||
const CTransaction &tx = *ws.m_ptx; | const CTransaction &tx = *ws.m_ptx; | ||||
const TxId &txid = tx.GetId(); | const TxId &txid = tx.GetId(); | ||||
TxValidationState &state = ws.m_state; | TxValidationState &state = ws.m_state; | ||||
// Check again against the next block's script verification flags | // Check again against the next block's script verification flags | ||||
// to cache our script execution flags. | // to cache our script execution flags. | ||||
// | // | ||||
// This is also useful in case of bugs in the standard flags that cause | // This is also useful in case of bugs in the standard flags that cause | ||||
Show All 26 Lines | if (ws.m_sig_checks_standard != nSigChecksConsensus) { | ||||
"%s: BUG! PLEASE REPORT THIS! SigChecks count differed between " | "%s: BUG! PLEASE REPORT THIS! SigChecks count differed between " | ||||
"standard and consensus flags in %s", | "standard and consensus flags in %s", | ||||
__func__, txid.ToString()); | __func__, txid.ToString()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool MemPoolAccept::Finalize(const ATMPArgs &args, Workspace &ws) { | bool MemPoolAccept::Finalize(const ATMPArgs &args, Workspace &ws) { | ||||
AssertLockHeld(cs_main); | |||||
AssertLockHeld(m_pool.cs); | |||||
const TxId &txid = ws.m_ptx->GetId(); | const TxId &txid = ws.m_ptx->GetId(); | ||||
TxValidationState &state = ws.m_state; | TxValidationState &state = ws.m_state; | ||||
const bool bypass_limits = args.m_bypass_limits; | const bool bypass_limits = args.m_bypass_limits; | ||||
std::unique_ptr<CTxMemPoolEntry> &entry = ws.m_entry; | std::unique_ptr<CTxMemPoolEntry> &entry = ws.m_entry; | ||||
// Store transaction in memory. | // Store transaction in memory. | ||||
m_pool.addUnchecked(*entry, ws.m_ancestors); | m_pool.addUnchecked(*entry, ws.m_ancestors); | ||||
▲ Show 20 Lines • Show All 326 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
} // namespace | } // namespace | ||||
MempoolAcceptResult AcceptToMemoryPool(const Config &config, | MempoolAcceptResult AcceptToMemoryPool(const Config &config, | ||||
CChainState &active_chainstate, | CChainState &active_chainstate, | ||||
const CTransactionRef &tx, | const CTransactionRef &tx, | ||||
int64_t accept_time, bool bypass_limits, | int64_t accept_time, bool bypass_limits, | ||||
bool test_accept) { | bool test_accept) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(::cs_main); | ||||
assert(active_chainstate.GetMempool() != nullptr); | assert(active_chainstate.GetMempool() != nullptr); | ||||
CTxMemPool &pool{*active_chainstate.GetMempool()}; | CTxMemPool &pool{*active_chainstate.GetMempool()}; | ||||
std::vector<COutPoint> coins_to_uncache; | std::vector<COutPoint> coins_to_uncache; | ||||
auto args = MemPoolAccept::ATMPArgs::SingleAccept( | auto args = MemPoolAccept::ATMPArgs::SingleAccept( | ||||
config, accept_time, bypass_limits, coins_to_uncache, test_accept); | config, accept_time, bypass_limits, coins_to_uncache, test_accept); | ||||
const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate) | const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate) | ||||
.AcceptSingleTransaction(tx, args); | .AcceptSingleTransaction(tx, args); | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
CoinsViews::CoinsViews(std::string ldb_name, size_t cache_size_bytes, | CoinsViews::CoinsViews(std::string ldb_name, size_t cache_size_bytes, | ||||
bool in_memory, bool should_wipe) | bool in_memory, bool should_wipe) | ||||
: m_dbview(gArgs.GetDataDirNet() / ldb_name, cache_size_bytes, in_memory, | : m_dbview(gArgs.GetDataDirNet() / ldb_name, cache_size_bytes, in_memory, | ||||
should_wipe), | should_wipe), | ||||
m_catcherview(&m_dbview) {} | m_catcherview(&m_dbview) {} | ||||
void CoinsViews::InitCache() { | void CoinsViews::InitCache() { | ||||
AssertLockHeld(::cs_main); | |||||
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview); | m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview); | ||||
} | } | ||||
CChainState::CChainState(CTxMemPool *mempool, BlockManager &blockman, | CChainState::CChainState(CTxMemPool *mempool, BlockManager &blockman, | ||||
ChainstateManager &chainman, | ChainstateManager &chainman, | ||||
std::optional<BlockHash> from_snapshot_blockhash) | std::optional<BlockHash> from_snapshot_blockhash) | ||||
: m_mempool(mempool), m_blockman(blockman), m_params(::Params()), | : m_mempool(mempool), m_blockman(blockman), m_params(::Params()), | ||||
m_chainman(chainman), m_from_snapshot_blockhash(from_snapshot_blockhash) { | m_chainman(chainman), m_from_snapshot_blockhash(from_snapshot_blockhash) { | ||||
} | } | ||||
void CChainState::InitCoinsDB(size_t cache_size_bytes, bool in_memory, | void CChainState::InitCoinsDB(size_t cache_size_bytes, bool in_memory, | ||||
bool should_wipe, std::string leveldb_name) { | bool should_wipe, std::string leveldb_name) { | ||||
if (m_from_snapshot_blockhash) { | if (m_from_snapshot_blockhash) { | ||||
leveldb_name += "_" + m_from_snapshot_blockhash->ToString(); | leveldb_name += "_" + m_from_snapshot_blockhash->ToString(); | ||||
} | } | ||||
m_coins_views = std::make_unique<CoinsViews>(leveldb_name, cache_size_bytes, | m_coins_views = std::make_unique<CoinsViews>(leveldb_name, cache_size_bytes, | ||||
in_memory, should_wipe); | in_memory, should_wipe); | ||||
} | } | ||||
void CChainState::InitCoinsCache(size_t cache_size_bytes) { | void CChainState::InitCoinsCache(size_t cache_size_bytes) { | ||||
AssertLockHeld(::cs_main); | |||||
assert(m_coins_views != nullptr); | assert(m_coins_views != nullptr); | ||||
m_coinstip_cache_size_bytes = cache_size_bytes; | m_coinstip_cache_size_bytes = cache_size_bytes; | ||||
m_coins_views->InitCache(); | m_coins_views->InitCache(); | ||||
} | } | ||||
// Note that though this is marked const, we may end up modifying | // Note that though this is marked const, we may end up modifying | ||||
// `m_cached_finished_ibd`, which is a performance-related implementation | // `m_cached_finished_ibd`, which is a performance-related implementation | ||||
// detail. This function must be marked `const` so that `CValidationInterface` | // detail. This function must be marked `const` so that `CValidationInterface` | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | LogPrintf("%s: current best=%s height=%d log2_work=%f date=%s\n", | ||||
log(tip->nChainWork.getdouble()) / log(2.0), | log(tip->nChainWork.getdouble()) / log(2.0), | ||||
FormatISO8601DateTime(tip->GetBlockTime())); | FormatISO8601DateTime(tip->GetBlockTime())); | ||||
} | } | ||||
// Same as InvalidChainFound, above, except not called directly from | // Same as InvalidChainFound, above, except not called directly from | ||||
// InvalidateBlock, which does its own setBlockIndexCandidates management. | // InvalidateBlock, which does its own setBlockIndexCandidates management. | ||||
void CChainState::InvalidBlockFound(CBlockIndex *pindex, | void CChainState::InvalidBlockFound(CBlockIndex *pindex, | ||||
const BlockValidationState &state) { | const BlockValidationState &state) { | ||||
AssertLockHeld(cs_main); | |||||
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | ||||
pindex->nStatus = pindex->nStatus.withFailed(); | pindex->nStatus = pindex->nStatus.withFailed(); | ||||
m_chainman.m_failed_blocks.insert(pindex); | m_chainman.m_failed_blocks.insert(pindex); | ||||
m_blockman.m_dirty_blockindex.insert(pindex); | m_blockman.m_dirty_blockindex.insert(pindex); | ||||
InvalidChainFound(pindex); | InvalidChainFound(pindex); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 809 Lines • ▼ Show 20 Lines | TRACE6(validation, block_connected, block_hash.data(), pindex->nHeight, | ||||
block.vtx.size(), nInputs, nSigChecksRet, | block.vtx.size(), nInputs, nSigChecksRet, | ||||
// in microseconds (µs) | // in microseconds (µs) | ||||
nTime5 - nTimeStart); | nTime5 - nTimeStart); | ||||
return true; | return true; | ||||
} | } | ||||
CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() { | CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() { | ||||
AssertLockHeld(::cs_main); | |||||
return this->GetCoinsCacheSizeState( | return this->GetCoinsCacheSizeState( | ||||
m_coinstip_cache_size_bytes, | m_coinstip_cache_size_bytes, | ||||
gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); | gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); | ||||
} | } | ||||
CoinsCacheSizeState | CoinsCacheSizeState | ||||
CChainState::GetCoinsCacheSizeState(size_t max_coins_cache_size_bytes, | CChainState::GetCoinsCacheSizeState(size_t max_coins_cache_size_bytes, | ||||
size_t max_mempool_size_bytes) { | size_t max_mempool_size_bytes) { | ||||
AssertLockHeld(::cs_main); | |||||
int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0; | int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0; | ||||
int64_t cacheSize = CoinsTip().DynamicMemoryUsage(); | int64_t cacheSize = CoinsTip().DynamicMemoryUsage(); | ||||
int64_t nTotalSpace = | int64_t nTotalSpace = | ||||
max_coins_cache_size_bytes + | max_coins_cache_size_bytes + | ||||
std::max<int64_t>(int64_t(max_mempool_size_bytes) - nMempoolUsage, 0); | std::max<int64_t>(int64_t(max_mempool_size_bytes) - nMempoolUsage, 0); | ||||
//! No need to periodic flush if at least this much space still available. | //! No need to periodic flush if at least this much space still available. | ||||
static constexpr int64_t MAX_BLOCK_COINSDB_USAGE_BYTES = | static constexpr int64_t MAX_BLOCK_COINSDB_USAGE_BYTES = | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | LogPrintf("%s%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%ld " | ||||
tip->GetChainTxCount(), | tip->GetChainTxCount(), | ||||
FormatISO8601DateTime(tip->GetBlockTime()), | FormatISO8601DateTime(tip->GetBlockTime()), | ||||
GuessVerificationProgress(params.TxData(), tip), | GuessVerificationProgress(params.TxData(), tip), | ||||
coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)), | coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)), | ||||
coins_tip.GetCacheSize()); | coins_tip.GetCacheSize()); | ||||
} | } | ||||
void CChainState::UpdateTip(const CBlockIndex *pindexNew) { | void CChainState::UpdateTip(const CBlockIndex *pindexNew) { | ||||
AssertLockHeld(::cs_main); | |||||
const auto &coins_tip = CoinsTip(); | const auto &coins_tip = CoinsTip(); | ||||
// The remainder of the function isn't relevant if we are not acting on | // The remainder of the function isn't relevant if we are not acting on | ||||
// the active chainstate, so return if need be. | // the active chainstate, so return if need be. | ||||
if (this != &m_chainman.ActiveChainstate()) { | if (this != &m_chainman.ActiveChainstate()) { | ||||
// Only log every so often so that we don't bury log messages at the | // Only log every so often so that we don't bury log messages at the | ||||
// tip. | // tip. | ||||
constexpr int BACKGROUND_LOG_INTERVAL = 2000; | constexpr int BACKGROUND_LOG_INTERVAL = 2000; | ||||
▲ Show 20 Lines • Show All 361 Lines • ▼ Show 20 Lines | bool CChainState::ConnectTip(const Config &config, BlockValidationState &state, | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Return the tip of the chain with the most work in it, that isn't known to be | * Return the tip of the chain with the most work in it, that isn't known to be | ||||
* invalid (it's however far from certain to be valid). | * invalid (it's however far from certain to be valid). | ||||
*/ | */ | ||||
CBlockIndex *CChainState::FindMostWorkChain() { | CBlockIndex *CChainState::FindMostWorkChain() { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(::cs_main); | ||||
do { | do { | ||||
CBlockIndex *pindexNew = nullptr; | CBlockIndex *pindexNew = nullptr; | ||||
// Find the best candidate header. | // Find the best candidate header. | ||||
{ | { | ||||
std::set<CBlockIndex *, CBlockIndexWorkComparator>::reverse_iterator | std::set<CBlockIndex *, CBlockIndexWorkComparator>::reverse_iterator | ||||
it = setBlockIndexCandidates.rbegin(); | it = setBlockIndexCandidates.rbegin(); | ||||
if (it == setBlockIndexCandidates.rend()) { | if (it == setBlockIndexCandidates.rend()) { | ||||
▲ Show 20 Lines • Show All 348 Lines • ▼ Show 20 Lines | bool CChainState::ActivateBestChain(const Config &config, | ||||
BlockValidationState &state, | BlockValidationState &state, | ||||
std::shared_ptr<const CBlock> pblock) { | std::shared_ptr<const CBlock> pblock) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
// Note that while we're often called here from ProcessNewBlock, this is | // Note that while we're often called here from ProcessNewBlock, this is | ||||
// far from a guarantee. Things in the P2P/RPC will often end up calling | // far from a guarantee. Things in the P2P/RPC will often end up calling | ||||
// us in the middle of ProcessNewBlock - do not assume pblock is set | // us in the middle of ProcessNewBlock - do not assume pblock is set | ||||
// sanely for performance or correctness! | // sanely for performance or correctness! | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(::cs_main); | ||||
// ABC maintains a fair degree of expensive-to-calculate internal state | // ABC maintains a fair degree of expensive-to-calculate internal state | ||||
// because this function periodically releases cs_main so that it does not | // because this function periodically releases cs_main so that it does not | ||||
// lock up other threads for too long during large connects - and to allow | // lock up other threads for too long during large connects - and to allow | ||||
// for e.g. the callback queue to drain we use m_chainstate_mutex to enforce | // for e.g. the callback queue to drain we use m_chainstate_mutex to enforce | ||||
// mutual exclusion so that only one caller may execute this function at a | // mutual exclusion so that only one caller may execute this function at a | ||||
// time | // time | ||||
LOCK(m_chainstate_mutex); | LOCK(m_chainstate_mutex); | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | bool CChainState::ActivateBestChain(const Config &config, | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CChainState::PreciousBlock(const Config &config, | bool CChainState::PreciousBlock(const Config &config, | ||||
BlockValidationState &state, | BlockValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | |||||
AssertLockNotHeld(::cs_main); | |||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (pindex->nChainWork < m_chain.Tip()->nChainWork) { | if (pindex->nChainWork < m_chain.Tip()->nChainWork) { | ||||
// Nothing to do, this block is not at the tip. | // Nothing to do, this block is not at the tip. | ||||
return true; | return true; | ||||
} | } | ||||
if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) { | if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) { | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | bool CChainState::UnwindBlock(const Config &config, BlockValidationState &state, | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CChainState::InvalidateBlock(const Config &config, | bool CChainState::InvalidateBlock(const Config &config, | ||||
BlockValidationState &state, | BlockValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
AssertLockNotHeld(::cs_main); | |||||
// See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | // See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | ||||
LOCK(m_chainstate_mutex); | LOCK(m_chainstate_mutex); | ||||
return UnwindBlock(config, state, pindex, true); | return UnwindBlock(config, state, pindex, true); | ||||
} | } | ||||
bool CChainState::ParkBlock(const Config &config, BlockValidationState &state, | bool CChainState::ParkBlock(const Config &config, BlockValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
AssertLockNotHeld(::cs_main); | |||||
// See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | // See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | ||||
LOCK(m_chainstate_mutex); | LOCK(m_chainstate_mutex); | ||||
return UnwindBlock(config, state, pindex, false); | return UnwindBlock(config, state, pindex, false); | ||||
} | } | ||||
bool CChainState::FinalizeBlock(const Config &config, | bool CChainState::FinalizeBlock(const Config &config, | ||||
BlockValidationState &state, | BlockValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
AssertLockNotHeld(::cs_main); | |||||
// See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | // See 'Note for backport of Core PR16849' in CChainState::UnwindBlock | ||||
LOCK(m_chainstate_mutex); | LOCK(m_chainstate_mutex); | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
CBlockIndex *pindexToInvalidate = nullptr; | CBlockIndex *pindexToInvalidate = nullptr; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (!MarkBlockAsFinal(state, pindex)) { | if (!MarkBlockAsFinal(state, pindex)) { | ||||
▲ Show 20 Lines • Show All 360 Lines • ▼ Show 20 Lines | |||||
* in ConnectBlock(). | * in ConnectBlock(). | ||||
* Note that -reindex-chainstate skips the validation that happens here! | * Note that -reindex-chainstate skips the validation that happens here! | ||||
*/ | */ | ||||
static bool | static bool | ||||
ContextualCheckBlockHeader(const CChainParams ¶ms, | ContextualCheckBlockHeader(const CChainParams ¶ms, | ||||
const CBlockHeader &block, | const CBlockHeader &block, | ||||
BlockValidationState &state, BlockManager &blockman, | BlockValidationState &state, BlockManager &blockman, | ||||
const CBlockIndex *pindexPrev, int64_t nAdjustedTime) | const CBlockIndex *pindexPrev, int64_t nAdjustedTime) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { | ||||
AssertLockHeld(::cs_main); | |||||
assert(pindexPrev != nullptr); | assert(pindexPrev != nullptr); | ||||
const int nHeight = pindexPrev->nHeight + 1; | const int nHeight = pindexPrev->nHeight + 1; | ||||
// Check proof of work | // Check proof of work | ||||
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, params)) { | if (block.nBits != GetNextWorkRequired(pindexPrev, &block, params)) { | ||||
LogPrintf("bad bits after height: %d\n", pindexPrev->nHeight); | LogPrintf("bad bits after height: %d\n", pindexPrev->nHeight); | ||||
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, | return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, | ||||
"bad-diffbits", "incorrect proof of work"); | "bad-diffbits", "incorrect proof of work"); | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | bool ChainstateManager::ProcessNewBlock( | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
MempoolAcceptResult | MempoolAcceptResult | ||||
ChainstateManager::ProcessTransaction(const CTransactionRef &tx, | ChainstateManager::ProcessTransaction(const CTransactionRef &tx, | ||||
bool test_accept) { | bool test_accept) { | ||||
AssertLockHeld(cs_main); | |||||
CChainState &active_chainstate = ActiveChainstate(); | CChainState &active_chainstate = ActiveChainstate(); | ||||
if (!active_chainstate.GetMempool()) { | if (!active_chainstate.GetMempool()) { | ||||
TxValidationState state; | TxValidationState state; | ||||
state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); | state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); | ||||
return MempoolAcceptResult::Failure(state); | return MempoolAcceptResult::Failure(state); | ||||
} | } | ||||
// Use GetConfig() temporarily. It will be removed in a follow-up by | // Use GetConfig() temporarily. It will be removed in a follow-up by | ||||
// making AcceptToMemoryPool take a CChainParams instead of a Config. | // making AcceptToMemoryPool take a CChainParams instead of a Config. | ||||
▲ Show 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/** | /** | ||||
* Apply the effects of a block on the utxo cache, ignoring that it may already | * Apply the effects of a block on the utxo cache, ignoring that it may already | ||||
* have been applied. | * have been applied. | ||||
*/ | */ | ||||
bool CChainState::RollforwardBlock(const CBlockIndex *pindex, | bool CChainState::RollforwardBlock(const CBlockIndex *pindex, | ||||
CCoinsViewCache &view) { | CCoinsViewCache &view) { | ||||
AssertLockHeld(cs_main); | |||||
// TODO: merge with ConnectBlock | // TODO: merge with ConnectBlock | ||||
CBlock block; | CBlock block; | ||||
if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) { | if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) { | ||||
return error("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s", | return error("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
for (const CTransactionRef &tx : block.vtx) { | for (const CTransactionRef &tx : block.vtx) { | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | bool CChainState::ReplayBlocks() { | ||||
cache.Flush(); | cache.Flush(); | ||||
uiInterface.ShowProgress("", 100, false); | uiInterface.ShowProgress("", 100, false); | ||||
return true; | return true; | ||||
} | } | ||||
// May NOT be used after any connections are up as much of the peer-processing | // May NOT be used after any connections are up as much of the peer-processing | ||||
// logic assumes a consistent block index state | // logic assumes a consistent block index state | ||||
void CChainState::UnloadBlockIndex() { | void CChainState::UnloadBlockIndex() { | ||||
AssertLockHeld(::cs_main); | |||||
nBlockSequenceId = 1; | nBlockSequenceId = 1; | ||||
setBlockIndexCandidates.clear(); | setBlockIndexCandidates.clear(); | ||||
// Do not point to CBlockIndex that will be free'd | // Do not point to CBlockIndex that will be free'd | ||||
m_finalizedBlockIndex = nullptr; | m_finalizedBlockIndex = nullptr; | ||||
} | } | ||||
// May NOT be used after any connections are up as much | // May NOT be used after any connections are up as much | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | try { | ||||
e.what()); | e.what()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void CChainState::LoadExternalBlockFile(const Config &config, FILE *fileIn, | void CChainState::LoadExternalBlockFile(const Config &config, FILE *fileIn, | ||||
FlatFilePos *dbp) { | FlatFilePos *dbp) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | |||||
// Map of disk positions for blocks with unknown parent (only used for | // Map of disk positions for blocks with unknown parent (only used for | ||||
// reindex) | // reindex) | ||||
static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent; | static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent; | ||||
int64_t nStart = GetTimeMillis(); | int64_t nStart = GetTimeMillis(); | ||||
int nLoaded = 0; | int nLoaded = 0; | ||||
try { | try { | ||||
// This takes over fileIn and calls fclose() on it in the CBufferedFile | // This takes over fileIn and calls fclose() on it in the CBufferedFile | ||||
▲ Show 20 Lines • Show All 481 Lines • ▼ Show 20 Lines | while (pindex != nullptr) { | ||||
} | } | ||||
} | } | ||||
// Check that we actually traversed the entire map. | // Check that we actually traversed the entire map. | ||||
assert(nNodes == forward.size()); | assert(nNodes == forward.size()); | ||||
} | } | ||||
std::string CChainState::ToString() { | std::string CChainState::ToString() { | ||||
AssertLockHeld(::cs_main); | |||||
CBlockIndex *tip = m_chain.Tip(); | CBlockIndex *tip = m_chain.Tip(); | ||||
return strprintf("Chainstate [%s] @ height %d (%s)", | return strprintf("Chainstate [%s] @ height %d (%s)", | ||||
m_from_snapshot_blockhash ? "snapshot" : "ibd", | m_from_snapshot_blockhash ? "snapshot" : "ibd", | ||||
tip ? tip->nHeight : -1, | tip ? tip->nHeight : -1, | ||||
tip ? tip->GetBlockHash().ToString() : "null"); | tip ? tip->GetBlockHash().ToString() : "null"); | ||||
} | } | ||||
bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) { | bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) { | ||||
AssertLockHeld(::cs_main); | |||||
if (coinstip_size == m_coinstip_cache_size_bytes && | if (coinstip_size == m_coinstip_cache_size_bytes && | ||||
coinsdb_size == m_coinsdb_cache_size_bytes) { | coinsdb_size == m_coinsdb_cache_size_bytes) { | ||||
// Cache sizes are unchanged, no need to continue. | // Cache sizes are unchanged, no need to continue. | ||||
return true; | return true; | ||||
} | } | ||||
size_t old_coinstip_size = m_coinstip_cache_size_bytes; | size_t old_coinstip_size = m_coinstip_cache_size_bytes; | ||||
m_coinstip_cache_size_bytes = coinstip_size; | m_coinstip_cache_size_bytes = coinstip_size; | ||||
m_coinsdb_cache_size_bytes = coinsdb_size; | m_coinsdb_cache_size_bytes = coinsdb_size; | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | if (m_snapshot_chainstate) { | ||||
out.push_back(m_snapshot_chainstate.get()); | out.push_back(m_snapshot_chainstate.get()); | ||||
} | } | ||||
return out; | return out; | ||||
} | } | ||||
CChainState &ChainstateManager::InitializeChainstate( | CChainState &ChainstateManager::InitializeChainstate( | ||||
CTxMemPool *mempool, const std::optional<BlockHash> &snapshot_blockhash) { | CTxMemPool *mempool, const std::optional<BlockHash> &snapshot_blockhash) { | ||||
AssertLockHeld(::cs_main); | |||||
bool is_snapshot = snapshot_blockhash.has_value(); | bool is_snapshot = snapshot_blockhash.has_value(); | ||||
std::unique_ptr<CChainState> &to_modify = | std::unique_ptr<CChainState> &to_modify = | ||||
is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; | is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; | ||||
if (to_modify) { | if (to_modify) { | ||||
throw std::logic_error("should not be overwriting a chainstate"); | throw std::logic_error("should not be overwriting a chainstate"); | ||||
} | } | ||||
to_modify.reset( | to_modify.reset( | ||||
▲ Show 20 Lines • Show All 337 Lines • ▼ Show 20 Lines | |||||
bool ChainstateManager::IsSnapshotActive() const { | bool ChainstateManager::IsSnapshotActive() const { | ||||
LOCK(::cs_main); | LOCK(::cs_main); | ||||
return m_snapshot_chainstate && | return m_snapshot_chainstate && | ||||
m_active_chainstate == m_snapshot_chainstate.get(); | m_active_chainstate == m_snapshot_chainstate.get(); | ||||
} | } | ||||
void ChainstateManager::Unload() { | void ChainstateManager::Unload() { | ||||
AssertLockHeld(::cs_main); | |||||
for (CChainState *chainstate : this->GetAll()) { | for (CChainState *chainstate : this->GetAll()) { | ||||
chainstate->m_chain.SetTip(nullptr); | chainstate->m_chain.SetTip(nullptr); | ||||
chainstate->UnloadBlockIndex(); | chainstate->UnloadBlockIndex(); | ||||
} | } | ||||
m_failed_blocks.clear(); | m_failed_blocks.clear(); | ||||
m_blockman.Unload(); | m_blockman.Unload(); | ||||
m_best_invalid = nullptr; | m_best_invalid = nullptr; | ||||
m_best_parked = nullptr; | m_best_parked = nullptr; | ||||
} | } | ||||
void ChainstateManager::Reset() { | void ChainstateManager::Reset() { | ||||
LOCK(::cs_main); | LOCK(::cs_main); | ||||
m_ibd_chainstate.reset(); | m_ibd_chainstate.reset(); | ||||
m_snapshot_chainstate.reset(); | m_snapshot_chainstate.reset(); | ||||
m_active_chainstate = nullptr; | m_active_chainstate = nullptr; | ||||
m_snapshot_validated = false; | m_snapshot_validated = false; | ||||
} | } | ||||
void ChainstateManager::MaybeRebalanceCaches() { | void ChainstateManager::MaybeRebalanceCaches() { | ||||
AssertLockHeld(::cs_main); | |||||
if (m_ibd_chainstate && !m_snapshot_chainstate) { | if (m_ibd_chainstate && !m_snapshot_chainstate) { | ||||
LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n"); | LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n"); | ||||
// Allocate everything to the IBD chainstate. | // Allocate everything to the IBD chainstate. | ||||
m_ibd_chainstate->ResizeCoinsCaches(m_total_coinstip_cache, | m_ibd_chainstate->ResizeCoinsCaches(m_total_coinstip_cache, | ||||
m_total_coinsdb_cache); | m_total_coinsdb_cache); | ||||
} else if (m_snapshot_chainstate && !m_ibd_chainstate) { | } else if (m_snapshot_chainstate && !m_ibd_chainstate) { | ||||
LogPrintf( | LogPrintf( | ||||
"[snapshot] allocating all cache to the snapshot chainstate\n"); | "[snapshot] allocating all cache to the snapshot chainstate\n"); | ||||
Show All 22 Lines |