mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-26 11:13:23 -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
|
## 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
|
- The concept of UTXO snapshots is treated as an implementation detail that lives
|
||||||
behind the ChainstateManager interface. The external presentation of the changes
|
behind the ChainstateManager interface. The external presentation of the changes
|
||||||
required to facilitate the use of UTXO snapshots is the understanding that there are
|
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
|
now certain regions of the chain that can be temporarily assumed to be valid.
|
||||||
the nStatus flag mentioned above). In certain cases, e.g. wallet rescanning, this is
|
In certain cases, e.g. wallet rescanning, this is very similar to dealing with
|
||||||
very similar to dealing with a pruned chain.
|
a pruned chain.
|
||||||
|
|
||||||
Logic outside ChainstateManager should try not to know about snapshots, instead
|
Logic outside ChainstateManager should try not to know about snapshots, instead
|
||||||
preferring to work in terms of more general states like assumed-valid.
|
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
|
BLOCK_OPT_WITNESS = 128, //!< block data in blk*.dat was received with a witness-enforcing client
|
||||||
|
|
||||||
/**
|
BLOCK_STATUS_RESERVED = 256, //!< Unused flag that was previously set on assumeutxo snapshot blocks and their
|
||||||
* If ASSUMED_VALID is set, it means that this block has not been validated
|
//!< ancestors before they were validated, and unset when they were 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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The block chain is a tree shaped structure starting with the
|
/** The block chain is a tree shaped structure starting with the
|
||||||
|
@ -316,14 +303,6 @@ public:
|
||||||
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
|
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.
|
//! Raise the validity level of this block index entry.
|
||||||
//! Returns true if the validity was changed.
|
//! Returns true if the validity was changed.
|
||||||
bool RaiseValidity(enum BlockStatus nUpTo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
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_FAILED_MASK) return false;
|
||||||
|
|
||||||
if ((nStatus & BLOCK_VALID_MASK) < nUpTo) {
|
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;
|
nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,9 +276,6 @@ struct SnapshotTestSetup : TestChain100Setup {
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
*node::ReadSnapshotBaseBlockhash(found),
|
*node::ReadSnapshotBaseBlockhash(found),
|
||||||
*chainman.SnapshotBlockhash());
|
*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);
|
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,
|
//! - First, verify that setBlockIndexCandidates is as expected when using a single,
|
||||||
//! fully-validating chainstate.
|
//! 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
|
//! 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,
|
//! 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.
|
//! 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();
|
Chainstate& cs1 = chainman.ActiveChainstate();
|
||||||
|
|
||||||
int num_indexes{0};
|
int num_indexes{0};
|
||||||
int num_assumed_valid{0};
|
|
||||||
// Blocks in range [assumed_valid_start_idx, last_assumed_valid_idx) will be
|
// Blocks in range [assumed_valid_start_idx, last_assumed_valid_idx) will be
|
||||||
// marked as assumed-valid and not having data.
|
// marked as assumed-valid and not having data.
|
||||||
const int expected_assumed_valid{20};
|
const int expected_assumed_valid{20};
|
||||||
|
@ -456,37 +452,30 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
|
||||||
reload_all_block_indexes();
|
reload_all_block_indexes();
|
||||||
BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), 1);
|
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) {
|
for (int i = 0; i <= cs1.m_chain.Height(); ++i) {
|
||||||
LOCK(::cs_main);
|
LOCK(::cs_main);
|
||||||
auto index = cs1.m_chain[i];
|
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) {
|
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->nTx = 0;
|
||||||
index->nChainTx = 0;
|
index->nChainTx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++num_indexes;
|
++num_indexes;
|
||||||
if (index->IsAssumedValid()) ++num_assumed_valid;
|
|
||||||
|
|
||||||
// Note the last fully-validated block as the expected validated tip.
|
// Note the last fully-validated block as the expected validated tip.
|
||||||
if (i == (assumed_valid_start_idx - 1)) {
|
if (i == (assumed_valid_start_idx - 1)) {
|
||||||
validated_tip = index;
|
validated_tip = index;
|
||||||
BOOST_CHECK(!index->IsAssumedValid());
|
|
||||||
}
|
}
|
||||||
// Note the last assumed valid block as the snapshot base
|
// Note the last assumed valid block as the snapshot base
|
||||||
if (i == last_assumed_valid_idx - 1) {
|
if (i == last_assumed_valid_idx - 1) {
|
||||||
assumed_base = index;
|
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.
|
// Note: cs2's tip is not set when ActivateExistingSnapshot is called.
|
||||||
Chainstate& cs2 = WITH_LOCK(::cs_main,
|
Chainstate& cs2 = WITH_LOCK(::cs_main,
|
||||||
return chainman.ActivateExistingSnapshot(*assumed_base->phashBlock));
|
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* 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* 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* 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
|
// After checking an assumeutxo snapshot block, reset pindexFirst pointers
|
||||||
// to earlier blocks that have not been downloaded or validated yet, so
|
// to earlier blocks that have not been downloaded or validated yet, so
|
||||||
|
@ -5068,7 +5067,6 @@ void ChainstateManager::CheckBlockIndex()
|
||||||
|
|
||||||
while (pindex != nullptr) {
|
while (pindex != nullptr) {
|
||||||
nNodes++;
|
nNodes++;
|
||||||
if (pindexFirstAssumeValid == nullptr && pindex->nStatus & BLOCK_ASSUMED_VALID) pindexFirstAssumeValid = pindex;
|
|
||||||
if (pindexFirstInvalid == nullptr && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
|
if (pindexFirstInvalid == nullptr && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
|
||||||
if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
||||||
pindexFirstMissing = pindex;
|
pindexFirstMissing = pindex;
|
||||||
|
@ -5115,7 +5113,7 @@ void ChainstateManager::CheckBlockIndex()
|
||||||
if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
|
if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
|
||||||
}
|
}
|
||||||
if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
|
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.
|
// Assumed-valid blocks should connect to the main chain.
|
||||||
assert((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE);
|
assert((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE);
|
||||||
}
|
}
|
||||||
|
@ -5271,7 +5269,6 @@ void ChainstateManager::CheckBlockIndex()
|
||||||
if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = nullptr;
|
if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = nullptr;
|
||||||
if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = nullptr;
|
if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = nullptr;
|
||||||
if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = nullptr;
|
if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = nullptr;
|
||||||
if (pindex == pindexFirstAssumeValid) pindexFirstAssumeValid = nullptr;
|
|
||||||
// Find our parent.
|
// Find our parent.
|
||||||
CBlockIndex* pindexPar = pindex->pprev;
|
CBlockIndex* pindexPar = pindex->pprev;
|
||||||
// Find which child we just visited.
|
// Find which child we just visited.
|
||||||
|
@ -5757,22 +5754,14 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
||||||
// Fake various pieces of CBlockIndex state:
|
// Fake various pieces of CBlockIndex state:
|
||||||
CBlockIndex* index = nullptr;
|
CBlockIndex* index = nullptr;
|
||||||
|
|
||||||
// Don't make any modifications to the genesis block.
|
// Don't make any modifications to the genesis block since it shouldn't be
|
||||||
// This is especially important because we don't want to erroneously
|
// neccessary, and since the genesis block doesn't have normal flags like
|
||||||
// apply BLOCK_ASSUMED_VALID to genesis, which would happen if we didn't skip
|
// BLOCK_VALID_SCRIPTS set.
|
||||||
// it here (since it apparently isn't BLOCK_VALID_SCRIPTS).
|
|
||||||
constexpr int AFTER_GENESIS_START{1};
|
constexpr int AFTER_GENESIS_START{1};
|
||||||
|
|
||||||
for (int i = AFTER_GENESIS_START; i <= snapshot_chainstate.m_chain.Height(); ++i) {
|
for (int i = AFTER_GENESIS_START; i <= snapshot_chainstate.m_chain.Height(); ++i) {
|
||||||
index = snapshot_chainstate.m_chain[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()
|
// Fake BLOCK_OPT_WITNESS so that Chainstate::NeedsRedownload()
|
||||||
// won't ask to rewind the entire assumed-valid chain on startup.
|
// won't ask to rewind the entire assumed-valid chain on startup.
|
||||||
if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) {
|
if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) {
|
||||||
|
|
|
@ -583,9 +583,10 @@ public:
|
||||||
const CBlockIndex* SnapshotBase() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
const CBlockIndex* SnapshotBase() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of all CBlockIndex entries with either BLOCK_VALID_TRANSACTIONS (for
|
* The set of all CBlockIndex entries that have as much work as our current
|
||||||
* itself and all ancestors) *or* BLOCK_ASSUMED_VALID (if using background
|
* tip or more, and transaction data needed to be validated (with
|
||||||
* chainstates) and as good as our current tip or better. Entries may be failed,
|
* 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.
|
* though, and pruning nodes may be missing the data for the block.
|
||||||
*/
|
*/
|
||||||
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
|
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
|
||||||
|
|
Loading…
Add table
Reference in a new issue