mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-08 21:59:10 +02:00
Merge bitcoin/bitcoin#29668: prune, rpc: Check undo data when finding pruneheight
8789dc8f31doc: Add note to getblockfrompeer on missing undo data (Fabian Jahr)4a1975008brpc: Make pruneheight also reflect undo data presence (Fabian Jahr)96b4facc91refactor, blockstorage: Generalize GetFirstStoredBlock (Fabian Jahr) Pull request description: The function `GetFirstStoredBlock()` helps us find the first block for which we have data. So far this function only looked for a block with `BLOCK_HAVE_DATA`. However, this doesn't mean that we also have the undo data of that block, and undo data might be required for what a user would like to do with those blocks. One example of how this might happen is if some blocks were fetched using the `getblockfrompeer` RPC. Blocks fetched from a peer will have data but no undo data. The first commit here allows `GetFirstStoredBlock()` to check for undo data as well by passing a parameter. This alone is useful for #29553 and I would use it there. In the second commit I am applying the undo check to the RPCs that report `pruneheight` to the user. I find this much more intuitive because I think the user expects to be able to do all operations on blocks up until the `pruneheight` but that is not the case if undo data is missing. I personally ran into this once before and now again when testing for assumeutxo when I had used `getblockfrompeer`. The following commit adds test coverage for this change of behavior. The last commit adds a note in the docs of `getblockfrompeer` that undo data will not be available. ACKs for top commit: achow101: ACK8789dc8f31furszy: Code review ACK8789dc8f31. stickies-v: ACK8789dc8f31Tree-SHA512: 90ae8bdd07a496ade579aa25240609c61c9ed173ad38d30533f6c631fe674e5a41727478ade69ca4b71a571ad94c9da4b33ebba6b5d8821109313c2de3bdfb3d
This commit is contained in:
@@ -594,12 +594,12 @@ bool BlockManager::IsBlockPruned(const CBlockIndex& block)
|
||||
return m_have_pruned && !(block.nStatus & BLOCK_HAVE_DATA) && (block.nTx > 0);
|
||||
}
|
||||
|
||||
const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& upper_block, const CBlockIndex* lower_block)
|
||||
const CBlockIndex* BlockManager::GetFirstBlock(const CBlockIndex& upper_block, uint32_t status_mask, const CBlockIndex* lower_block) const
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
const CBlockIndex* last_block = &upper_block;
|
||||
assert(last_block->nStatus & BLOCK_HAVE_DATA); // 'upper_block' must have data
|
||||
while (last_block->pprev && (last_block->pprev->nStatus & BLOCK_HAVE_DATA)) {
|
||||
assert((last_block->nStatus & status_mask) == status_mask); // 'upper_block' must satisfy the status mask
|
||||
while (last_block->pprev && ((last_block->pprev->nStatus & status_mask) == status_mask)) {
|
||||
if (lower_block) {
|
||||
// Return if we reached the lower_block
|
||||
if (last_block == lower_block) return lower_block;
|
||||
@@ -616,7 +616,7 @@ const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& upper_bl
|
||||
bool BlockManager::CheckBlockDataAvailability(const CBlockIndex& upper_block, const CBlockIndex& lower_block)
|
||||
{
|
||||
if (!(upper_block.nStatus & BLOCK_HAVE_DATA)) return false;
|
||||
return GetFirstStoredBlock(upper_block, &lower_block) == &lower_block;
|
||||
return GetFirstBlock(upper_block, BLOCK_HAVE_DATA, &lower_block) == &lower_block;
|
||||
}
|
||||
|
||||
// If we're using -prune with -reindex, then delete block files that will be ignored by the
|
||||
|
||||
@@ -372,10 +372,33 @@ public:
|
||||
//! (part of the same chain).
|
||||
bool CheckBlockDataAvailability(const CBlockIndex& upper_block LIFETIMEBOUND, const CBlockIndex& lower_block LIFETIMEBOUND) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
//! Find the first stored ancestor of start_block immediately after the last
|
||||
//! pruned ancestor. Return value will never be null. Caller is responsible
|
||||
//! for ensuring that start_block has data is not pruned.
|
||||
const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block LIFETIMEBOUND, const CBlockIndex* lower_block=nullptr) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
/**
|
||||
* @brief Returns the earliest block with specified `status_mask` flags set after
|
||||
* the latest block _not_ having those flags.
|
||||
*
|
||||
* This function starts from `upper_block`, which must have all
|
||||
* `status_mask` flags set, and iterates backwards through its ancestors. It
|
||||
* continues as long as each block has all `status_mask` flags set, until
|
||||
* reaching the oldest ancestor or `lower_block`.
|
||||
*
|
||||
* @pre `upper_block` must have all `status_mask` flags set.
|
||||
* @pre `lower_block` must be null or an ancestor of `upper_block`
|
||||
*
|
||||
* @param upper_block The starting block for the search, which must have all
|
||||
* `status_mask` flags set.
|
||||
* @param status_mask Bitmask specifying required status flags.
|
||||
* @param lower_block The earliest possible block to return. If null, the
|
||||
* search can extend to the genesis block.
|
||||
*
|
||||
* @return A non-null pointer to the earliest block between `upper_block`
|
||||
* and `lower_block`, inclusive, such that every block between the
|
||||
* returned block and `upper_block` has `status_mask` flags set.
|
||||
*/
|
||||
const CBlockIndex* GetFirstBlock(
|
||||
const CBlockIndex& upper_block LIFETIMEBOUND,
|
||||
uint32_t status_mask,
|
||||
const CBlockIndex* lower_block = nullptr
|
||||
) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
/** True if any block files have ever been pruned. */
|
||||
bool m_have_pruned = false;
|
||||
|
||||
Reference in New Issue
Block a user