mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 03:47:29 -03:00
assumeutxo: Remove BLOCK_ASSUMED_VALID flag
Flag adds complexity and is not currently used for anything.
This commit is contained in:
parent
ef174e9ed2
commit
9d9a7458a2
5 changed files with 17 additions and 71 deletions
|
@ -51,18 +51,12 @@ The utility script
|
|||
|
||||
## Design notes
|
||||
|
||||
- A new block index `nStatus` flag is introduced, `BLOCK_ASSUMED_VALID`, to mark block
|
||||
index entries that are required to be assumed-valid by a chainstate created
|
||||
from a UTXO snapshot. This flag is used as a way to modify certain
|
||||
CheckBlockIndex() logic to account for index entries that are pending validation by a
|
||||
chainstate running asynchronously in the background.
|
||||
|
||||
- The concept of UTXO snapshots is treated as an implementation detail that lives
|
||||
behind the ChainstateManager interface. The external presentation of the changes
|
||||
required to facilitate the use of UTXO snapshots is the understanding that there are
|
||||
now certain regions of the chain that can be temporarily assumed to be valid (using
|
||||
the nStatus flag mentioned above). In certain cases, e.g. wallet rescanning, this is
|
||||
very similar to dealing with a pruned chain.
|
||||
now certain regions of the chain that can be temporarily assumed to be valid.
|
||||
In certain cases, e.g. wallet rescanning, this is very similar to dealing with
|
||||
a pruned chain.
|
||||
|
||||
Logic outside ChainstateManager should try not to know about snapshots, instead
|
||||
preferring to work in terms of more general states like assumed-valid.
|
||||
|
|
31
src/chain.h
31
src/chain.h
|
@ -128,21 +128,8 @@ enum BlockStatus : uint32_t {
|
|||
|
||||
BLOCK_OPT_WITNESS = 128, //!< block data in blk*.dat was received with a witness-enforcing client
|
||||
|
||||
/**
|
||||
* If ASSUMED_VALID is set, it means that this block has not been validated
|
||||
* and has validity status less than VALID_SCRIPTS. Also that it may have
|
||||
* descendant blocks with VALID_SCRIPTS set, because they can be validated
|
||||
* based on an assumeutxo snapshot.
|
||||
*
|
||||
* When an assumeutxo snapshot is loaded, the ASSUMED_VALID flag is added to
|
||||
* unvalidated blocks at the snapshot height and below. Then, as the background
|
||||
* validation progresses, and these blocks are validated, the ASSUMED_VALID
|
||||
* flags are removed. See `doc/design/assumeutxo.md` for details.
|
||||
*
|
||||
* This flag is only used to implement checks in CheckBlockIndex() and
|
||||
* should not be used elsewhere.
|
||||
*/
|
||||
BLOCK_ASSUMED_VALID = 256,
|
||||
BLOCK_STATUS_RESERVED = 256, //!< Unused flag that was previously set on assumeutxo snapshot blocks and their
|
||||
//!< ancestors before they were validated, and unset when they were validated.
|
||||
};
|
||||
|
||||
/** The block chain is a tree shaped structure starting with the
|
||||
|
@ -316,14 +303,6 @@ public:
|
|||
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
|
||||
}
|
||||
|
||||
//! @returns true if the block is assumed-valid; this means it is queued to be
|
||||
//! validated by a background chainstate.
|
||||
bool IsAssumedValid() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
return nStatus & BLOCK_ASSUMED_VALID;
|
||||
}
|
||||
|
||||
//! Raise the validity level of this block index entry.
|
||||
//! Returns true if the validity was changed.
|
||||
bool RaiseValidity(enum BlockStatus nUpTo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
|
@ -333,12 +312,6 @@ public:
|
|||
if (nStatus & BLOCK_FAILED_MASK) return false;
|
||||
|
||||
if ((nStatus & BLOCK_VALID_MASK) < nUpTo) {
|
||||
// If this block had been marked assumed-valid and we're raising
|
||||
// its validity to a certain point, there is no longer an assumption.
|
||||
if (nStatus & BLOCK_ASSUMED_VALID && nUpTo >= BLOCK_VALID_SCRIPTS) {
|
||||
nStatus &= ~BLOCK_ASSUMED_VALID;
|
||||
}
|
||||
|
||||
nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -276,9 +276,6 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
BOOST_CHECK_EQUAL(
|
||||
*node::ReadSnapshotBaseBlockhash(found),
|
||||
*chainman.SnapshotBlockhash());
|
||||
|
||||
// Ensure that the genesis block was not marked assumed-valid.
|
||||
BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
|
||||
}
|
||||
|
||||
const auto& au_data = ::Params().AssumeutxoForHeight(snapshot_height);
|
||||
|
@ -410,7 +407,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, SnapshotTestSetup)
|
|||
//! - First, verify that setBlockIndexCandidates is as expected when using a single,
|
||||
//! fully-validating chainstate.
|
||||
//!
|
||||
//! - Then mark a region of the chain BLOCK_ASSUMED_VALID and introduce a second chainstate
|
||||
//! - Then mark a region of the chain as missing data and introduce a second chainstate
|
||||
//! that will tolerate assumed-valid blocks. Run LoadBlockIndex() and ensure that the first
|
||||
//! chainstate only contains fully validated blocks and the other chainstate contains all blocks,
|
||||
//! except those marked assume-valid, because those entries don't HAVE_DATA.
|
||||
|
@ -421,7 +418,6 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
|
|||
Chainstate& cs1 = chainman.ActiveChainstate();
|
||||
|
||||
int num_indexes{0};
|
||||
int num_assumed_valid{0};
|
||||
// Blocks in range [assumed_valid_start_idx, last_assumed_valid_idx) will be
|
||||
// marked as assumed-valid and not having data.
|
||||
const int expected_assumed_valid{20};
|
||||
|
@ -456,37 +452,30 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
|
|||
reload_all_block_indexes();
|
||||
BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), 1);
|
||||
|
||||
// Mark some region of the chain assumed-valid, and remove the HAVE_DATA flag.
|
||||
// Reset some region of the chain's nStatus, removing the HAVE_DATA flag.
|
||||
for (int i = 0; i <= cs1.m_chain.Height(); ++i) {
|
||||
LOCK(::cs_main);
|
||||
auto index = cs1.m_chain[i];
|
||||
|
||||
// Blocks with heights in range [91, 110] are marked ASSUMED_VALID
|
||||
// Blocks with heights in range [91, 110] are marked as missing data.
|
||||
if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {
|
||||
index->nStatus = BlockStatus::BLOCK_VALID_TREE | BlockStatus::BLOCK_ASSUMED_VALID;
|
||||
index->nStatus = BlockStatus::BLOCK_VALID_TREE;
|
||||
index->nTx = 0;
|
||||
index->nChainTx = 0;
|
||||
}
|
||||
|
||||
++num_indexes;
|
||||
if (index->IsAssumedValid()) ++num_assumed_valid;
|
||||
|
||||
// Note the last fully-validated block as the expected validated tip.
|
||||
if (i == (assumed_valid_start_idx - 1)) {
|
||||
validated_tip = index;
|
||||
BOOST_CHECK(!index->IsAssumedValid());
|
||||
}
|
||||
// Note the last assumed valid block as the snapshot base
|
||||
if (i == last_assumed_valid_idx - 1) {
|
||||
assumed_base = index;
|
||||
BOOST_CHECK(index->IsAssumedValid());
|
||||
} else if (i == last_assumed_valid_idx) {
|
||||
BOOST_CHECK(!index->IsAssumedValid());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(expected_assumed_valid, num_assumed_valid);
|
||||
|
||||
// Note: cs2's tip is not set when ActivateExistingSnapshot is called.
|
||||
Chainstate& cs2 = WITH_LOCK(::cs_main,
|
||||
return chainman.ActivateExistingSnapshot(*assumed_base->phashBlock));
|
||||
|
|
|
@ -5048,7 +5048,6 @@ void ChainstateManager::CheckBlockIndex()
|
|||
CBlockIndex* pindexFirstNotTransactionsValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not), since assumeutxo snapshot if used.
|
||||
CBlockIndex* pindexFirstNotChainValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not), since assumeutxo snapshot if used.
|
||||
CBlockIndex* pindexFirstNotScriptsValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not), since assumeutxo snapshot if used.
|
||||
CBlockIndex* pindexFirstAssumeValid = nullptr; // Oldest ancestor of pindex which has BLOCK_ASSUMED_VALID
|
||||
|
||||
// After checking an assumeutxo snapshot block, reset pindexFirst pointers
|
||||
// to earlier blocks that have not been downloaded or validated yet, so
|
||||
|
@ -5068,7 +5067,6 @@ void ChainstateManager::CheckBlockIndex()
|
|||
|
||||
while (pindex != nullptr) {
|
||||
nNodes++;
|
||||
if (pindexFirstAssumeValid == nullptr && pindex->nStatus & BLOCK_ASSUMED_VALID) pindexFirstAssumeValid = pindex;
|
||||
if (pindexFirstInvalid == nullptr && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
|
||||
if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
||||
pindexFirstMissing = pindex;
|
||||
|
@ -5115,7 +5113,7 @@ void ChainstateManager::CheckBlockIndex()
|
|||
if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
|
||||
}
|
||||
if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
|
||||
if (pindex->IsAssumedValid()) {
|
||||
if (snap_base && snap_base->GetAncestor(pindex->nHeight) == pindex) {
|
||||
// Assumed-valid blocks should connect to the main chain.
|
||||
assert((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE);
|
||||
}
|
||||
|
@ -5271,7 +5269,6 @@ void ChainstateManager::CheckBlockIndex()
|
|||
if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = nullptr;
|
||||
if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = nullptr;
|
||||
if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = nullptr;
|
||||
if (pindex == pindexFirstAssumeValid) pindexFirstAssumeValid = nullptr;
|
||||
// Find our parent.
|
||||
CBlockIndex* pindexPar = pindex->pprev;
|
||||
// Find which child we just visited.
|
||||
|
@ -5757,22 +5754,14 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
// Fake various pieces of CBlockIndex state:
|
||||
CBlockIndex* index = nullptr;
|
||||
|
||||
// Don't make any modifications to the genesis block.
|
||||
// This is especially important because we don't want to erroneously
|
||||
// apply BLOCK_ASSUMED_VALID to genesis, which would happen if we didn't skip
|
||||
// it here (since it apparently isn't BLOCK_VALID_SCRIPTS).
|
||||
// Don't make any modifications to the genesis block since it shouldn't be
|
||||
// neccessary, and since the genesis block doesn't have normal flags like
|
||||
// BLOCK_VALID_SCRIPTS set.
|
||||
constexpr int AFTER_GENESIS_START{1};
|
||||
|
||||
for (int i = AFTER_GENESIS_START; i <= snapshot_chainstate.m_chain.Height(); ++i) {
|
||||
index = snapshot_chainstate.m_chain[i];
|
||||
|
||||
// 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 Chainstate::NeedsRedownload()
|
||||
// won't ask to rewind the entire assumed-valid chain on startup.
|
||||
if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) {
|
||||
|
|
|
@ -583,9 +583,10 @@ public:
|
|||
const CBlockIndex* SnapshotBase() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
/**
|
||||
* The set of all CBlockIndex entries with either BLOCK_VALID_TRANSACTIONS (for
|
||||
* itself and all ancestors) *or* BLOCK_ASSUMED_VALID (if using background
|
||||
* chainstates) and as good as our current tip or better. Entries may be failed,
|
||||
* The set of all CBlockIndex entries that have as much work as our current
|
||||
* tip or more, and transaction data needed to be validated (with
|
||||
* BLOCK_VALID_TRANSACTIONS for each block and its parents back to the
|
||||
* genesis block or an assumeutxo snapshot block). Entries may be failed,
|
||||
* though, and pruning nodes may be missing the data for the block.
|
||||
*/
|
||||
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
|
||||
|
|
Loading…
Reference in a new issue