mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Merge b7e3600815 into merged_master (Bitcoin PR bitcoin/bitcoin#21526)
This commit is contained in:
commit
070c52dcef
10 changed files with 314 additions and 120 deletions
|
|
@ -1185,10 +1185,15 @@ void CoinsViews::InitCache()
|
|||
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
|
||||
}
|
||||
|
||||
CChainState::CChainState(CTxMemPool* mempool, BlockManager& blockman, std::optional<uint256> from_snapshot_blockhash)
|
||||
CChainState::CChainState(
|
||||
CTxMemPool* mempool,
|
||||
BlockManager& blockman,
|
||||
ChainstateManager& chainman,
|
||||
std::optional<uint256> from_snapshot_blockhash)
|
||||
: m_mempool(mempool),
|
||||
m_params(::Params()),
|
||||
m_blockman(blockman),
|
||||
m_chainman(chainman),
|
||||
m_from_snapshot_blockhash(from_snapshot_blockhash) {}
|
||||
|
||||
void CChainState::InitCoinsDB(
|
||||
|
|
@ -2340,8 +2345,42 @@ static void AppendWarning(bilingual_str& res, const bilingual_str& warn)
|
|||
res += warn;
|
||||
}
|
||||
|
||||
static void UpdateTipLog(
|
||||
const CCoinsViewCache& coins_tip,
|
||||
const CBlockIndex* tip,
|
||||
const CChainParams& params,
|
||||
const std::string& func_name,
|
||||
const std::string& prefix,
|
||||
const std::string& warning_messages) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
|
||||
AssertLockHeld(::cs_main);
|
||||
LogPrintf("%s%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n",
|
||||
prefix, func_name,
|
||||
tip->GetBlockHash().ToString(), tip->nHeight, tip->nVersion,
|
||||
log(tip->nChainWork.getdouble()) / log(2.0), (unsigned long)tip->nChainTx,
|
||||
FormatISO8601DateTime(tip->GetBlockTime()),
|
||||
GuessVerificationProgress(tip, params.GetConsensus().nPowTargetSpacing),
|
||||
coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)),
|
||||
coins_tip.GetCacheSize(),
|
||||
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages) : "");
|
||||
}
|
||||
|
||||
void CChainState::UpdateTip(const CBlockIndex* pindexNew)
|
||||
{
|
||||
const auto& coins_tip = this->CoinsTip();
|
||||
|
||||
// The remainder of the function isn't relevant if we are not acting on
|
||||
// the active chainstate, so return if need be.
|
||||
if (this != &m_chainman.ActiveChainstate()) {
|
||||
// Only log every so often so that we don't bury log messages at the tip.
|
||||
constexpr int BACKGROUND_LOG_INTERVAL = 2000;
|
||||
if (pindexNew->nHeight % BACKGROUND_LOG_INTERVAL == 0) {
|
||||
UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "[background validation] ", "");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// New best block
|
||||
if (m_mempool) {
|
||||
m_mempool->AddTransactionsUpdated(1);
|
||||
|
|
@ -2369,13 +2408,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
|
|||
}
|
||||
}
|
||||
}
|
||||
LogPrintf("%s: new best=%s height=%d version=0x%08x tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", __func__,
|
||||
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
|
||||
(unsigned long)pindexNew->nChainTx,
|
||||
FormatISO8601DateTime(pindexNew->GetBlockTime()),
|
||||
GuessVerificationProgress(pindexNew, m_params.GetConsensus().nPowTargetSpacing),
|
||||
this->CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), this->CoinsTip().GetCacheSize(),
|
||||
!warning_messages.empty() ? strprintf(" warning='%s'", warning_messages.original) : "");
|
||||
UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "", warning_messages.original);
|
||||
|
||||
// Do some logging if dynafed parameters changed.
|
||||
if (pindexNew->pprev && !pindexNew->dynafed_params().IsNull()) {
|
||||
|
|
@ -4067,7 +4100,9 @@ bool BlockManager::LoadBlockIndex(
|
|||
pindex->nStatus |= BLOCK_FAILED_CHILD;
|
||||
setDirtyBlockIndex.insert(pindex);
|
||||
}
|
||||
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr)) {
|
||||
if (pindex->IsAssumedValid() ||
|
||||
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
|
||||
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
|
||||
block_index_candidates.insert(pindex);
|
||||
}
|
||||
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
|
||||
|
|
@ -4647,12 +4682,33 @@ void CChainState::CheckBlockIndex()
|
|||
while (pindex != nullptr) {
|
||||
nNodes++;
|
||||
if (pindexFirstInvalid == nullptr && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
|
||||
if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex;
|
||||
// Assumed-valid index entries will not have data since we haven't downloaded the
|
||||
// full block yet.
|
||||
if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA) && !pindex->IsAssumedValid()) {
|
||||
pindexFirstMissing = pindex;
|
||||
}
|
||||
if (pindexFirstNeverProcessed == nullptr && pindex->nTx == 0) pindexFirstNeverProcessed = pindex;
|
||||
if (pindex->pprev != nullptr && pindexFirstNotTreeValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex;
|
||||
if (pindex->pprev != nullptr && pindexFirstNotTransactionsValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex;
|
||||
if (pindex->pprev != nullptr && pindexFirstNotChainValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex;
|
||||
if (pindex->pprev != nullptr && pindexFirstNotScriptsValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex;
|
||||
|
||||
if (pindex->pprev != nullptr && !pindex->IsAssumedValid()) {
|
||||
// Skip validity flag checks for BLOCK_ASSUMED_VALID index entries, since these
|
||||
// *_VALID_MASK flags will not be present for index entries we are temporarily assuming
|
||||
// valid.
|
||||
if (pindexFirstNotTransactionsValid == nullptr &&
|
||||
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) {
|
||||
pindexFirstNotTransactionsValid = pindex;
|
||||
}
|
||||
|
||||
if (pindexFirstNotChainValid == nullptr &&
|
||||
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) {
|
||||
pindexFirstNotChainValid = pindex;
|
||||
}
|
||||
|
||||
if (pindexFirstNotScriptsValid == nullptr &&
|
||||
(pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) {
|
||||
pindexFirstNotScriptsValid = pindex;
|
||||
}
|
||||
}
|
||||
|
||||
// Begin: actual consistency checks.
|
||||
if (pindex->pprev == nullptr) {
|
||||
|
|
@ -4663,7 +4719,9 @@ void CChainState::CheckBlockIndex()
|
|||
if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
|
||||
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
|
||||
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
|
||||
if (!fHavePruned) {
|
||||
// Unless these indexes are assumed valid and pending block download on a
|
||||
// background chainstate.
|
||||
if (!fHavePruned && !pindex->IsAssumedValid()) {
|
||||
// If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
|
||||
assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
|
||||
assert(pindexFirstMissing == pindexFirstNeverProcessed);
|
||||
|
|
@ -4672,7 +4730,16 @@ void CChainState::CheckBlockIndex()
|
|||
if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
|
||||
}
|
||||
if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
|
||||
assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent.
|
||||
if (pindex->IsAssumedValid()) {
|
||||
// Assumed-valid blocks should have some nTx value.
|
||||
assert(pindex->nTx > 0);
|
||||
// Assumed-valid blocks should connect to the main chain.
|
||||
assert((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE);
|
||||
} else {
|
||||
// Otherwise there should only be an nTx value if we have
|
||||
// actually seen a block's transactions.
|
||||
assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent.
|
||||
}
|
||||
// All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to HaveTxsDownloaded().
|
||||
assert((pindexFirstNeverProcessed == nullptr) == pindex->HaveTxsDownloaded());
|
||||
assert((pindexFirstNotTransactionsValid == nullptr) == pindex->HaveTxsDownloaded());
|
||||
|
|
@ -4689,11 +4756,17 @@ void CChainState::CheckBlockIndex()
|
|||
}
|
||||
if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && pindexFirstNeverProcessed == nullptr) {
|
||||
if (pindexFirstInvalid == nullptr) {
|
||||
const bool is_active = this == &m_chainman.ActiveChainstate();
|
||||
|
||||
// If this block sorts at least as good as the current tip and
|
||||
// is valid and we have all data for its parents, it must be in
|
||||
// setBlockIndexCandidates. m_chain.Tip() must also be there
|
||||
// even if some data has been pruned.
|
||||
if (pindexFirstMissing == nullptr || pindex == m_chain.Tip()) {
|
||||
//
|
||||
// Don't perform this check for the background chainstate since
|
||||
// its setBlockIndexCandidates shouldn't have some entries (i.e. those past the
|
||||
// snapshot block) which do exist in the block index for the active chainstate.
|
||||
if (is_active && (pindexFirstMissing == nullptr || pindex == m_chain.Tip())) {
|
||||
assert(setBlockIndexCandidates.count(pindex));
|
||||
}
|
||||
// If some parent is missing, then it could be that this block was in
|
||||
|
|
@ -5027,7 +5100,7 @@ CChainState& ChainstateManager::InitializeChainstate(
|
|||
if (to_modify) {
|
||||
throw std::logic_error("should not be overwriting a chainstate");
|
||||
}
|
||||
to_modify.reset(new CChainState(mempool, m_blockman, snapshot_blockhash));
|
||||
to_modify.reset(new CChainState(mempool, m_blockman, *this, snapshot_blockhash));
|
||||
|
||||
// Snapshot chainstates and initial IBD chaintates always become active.
|
||||
if (is_snapshot || (!is_snapshot && !m_active_chainstate)) {
|
||||
|
|
@ -5096,8 +5169,9 @@ bool ChainstateManager::ActivateSnapshot(
|
|||
static_cast<size_t>(current_coinsdb_cache_size * IBD_CACHE_PERC));
|
||||
}
|
||||
|
||||
auto snapshot_chainstate = WITH_LOCK(::cs_main, return std::make_unique<CChainState>(
|
||||
/* mempool */ nullptr, m_blockman, base_blockhash));
|
||||
auto snapshot_chainstate = WITH_LOCK(::cs_main,
|
||||
return std::make_unique<CChainState>(
|
||||
/* mempool */ nullptr, m_blockman, *this, base_blockhash));
|
||||
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
|
|
@ -5300,11 +5374,25 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
// Fake nChainTx so that GuessVerificationProgress reports accurately
|
||||
index->nChainTx = index->pprev ? index->pprev->nChainTx + index->nTx : 1;
|
||||
|
||||
// Mark unvalidated block index entries beneath the snapshot base block as assumed-valid.
|
||||
if (!index->IsValid(BLOCK_VALID_SCRIPTS)) {
|
||||
// This flag will be removed once the block is fully validated by a
|
||||
// background chainstate.
|
||||
index->nStatus |= BLOCK_ASSUMED_VALID;
|
||||
}
|
||||
|
||||
// Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload()
|
||||
// won't ask to rewind the entire assumed-valid chain on startup.
|
||||
if (index->pprev && DeploymentActiveAt(*index, ::Params().GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
|
||||
index->nStatus |= BLOCK_OPT_WITNESS;
|
||||
}
|
||||
|
||||
setDirtyBlockIndex.insert(index);
|
||||
// Changes to the block index will be flushed to disk after this call
|
||||
// returns in `ActivateSnapshot()`, when `MaybeRebalanceCaches()` is
|
||||
// called, since we've added a snapshot chainstate and therefore will
|
||||
// have to downsize the IBD chainstate, which will result in a call to
|
||||
// `FlushStateToDisk(ALWAYS)`.
|
||||
}
|
||||
|
||||
assert(index);
|
||||
|
|
@ -5329,22 +5417,6 @@ bool ChainstateManager::IsSnapshotActive() const
|
|||
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
|
||||
}
|
||||
|
||||
CChainState& ChainstateManager::ValidatedChainstate() const
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
if (m_snapshot_chainstate && IsSnapshotValidated()) {
|
||||
return *m_snapshot_chainstate.get();
|
||||
}
|
||||
assert(m_ibd_chainstate);
|
||||
return *m_ibd_chainstate.get();
|
||||
}
|
||||
|
||||
bool ChainstateManager::IsBackgroundIBD(CChainState* chainstate) const
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
return (m_snapshot_chainstate && chainstate == m_ibd_chainstate.get());
|
||||
}
|
||||
|
||||
void ChainstateManager::Unload()
|
||||
{
|
||||
for (CChainState* chainstate : this->GetAll()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue