Skip to content

backport: merge bitcoin#21727, #22371, #21526, #23174, #23785, #23581, #23974, #22932, #24050, #24515 (blockstorage backports) #6085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Makefile.test_util.include
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ EXTRA_LIBRARIES += \

TEST_UTIL_H = \
test/util/blockfilter.h \
test/util/chainstate.h \
test/util/index.h \
test/util/logging.h \
test/util/mining.h \
Expand Down
51 changes: 42 additions & 9 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <consensus/params.h>
#include <flatfile.h>
#include <primitives/block.h>
#include <sync.h>
#include <uint256.h>

#include <vector>
Expand All @@ -34,6 +35,8 @@ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
*/
static constexpr int64_t MAX_BLOCK_TIME_GAP = 25 * 60;

extern RecursiveMutex cs_main;

class CBlockFileInfo
{
public:
Expand Down Expand Up @@ -124,6 +127,14 @@ enum BlockStatus: uint32_t {
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,

BLOCK_CONFLICT_CHAINLOCK = 128, //!< conflicts with chainlock system

/**
* If set, this indicates that the block index entry is assumed-valid.
* Certain diagnostics will be skipped in e.g. CheckBlockIndex().
* It almost certainly means that the block's full validation is pending
* on a background chainstate. See `doc/assumeutxo.md`.
*/
BLOCK_ASSUMED_VALID = 256,
};

/** The block chain is a tree shaped structure starting with the
Expand All @@ -147,13 +158,13 @@ class CBlockIndex
int nHeight{0};

//! Which # file this block is stored in (blk?????.dat)
int nFile{0};
int nFile GUARDED_BY(::cs_main){0};

//! Byte offset within blk?????.dat where this block's data is stored
unsigned int nDataPos{0};
unsigned int nDataPos GUARDED_BY(::cs_main){0};

//! Byte offset within rev?????.dat where this block's undo data is stored
unsigned int nUndoPos{0};
unsigned int nUndoPos GUARDED_BY(::cs_main){0};

//! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
arith_uint256 nChainWork{};
Expand Down Expand Up @@ -181,7 +192,7 @@ class CBlockIndex
//! load to avoid the block index being spuriously rewound.
//! @sa NeedsRedownload
//! @sa ActivateSnapshot
uint32_t nStatus{0};
uint32_t nStatus GUARDED_BY(::cs_main){0};

//! block header
int32_t nVersion{0};
Expand Down Expand Up @@ -209,7 +220,9 @@ class CBlockIndex
{
}

FlatFilePos GetBlockPos() const {
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
FlatFilePos ret;
if (nStatus & BLOCK_HAVE_DATA) {
ret.nFile = nFile;
Expand All @@ -218,7 +231,9 @@ class CBlockIndex
return ret;
}

FlatFilePos GetUndoPos() const {
FlatFilePos GetUndoPos() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
FlatFilePos ret;
if (nStatus & BLOCK_HAVE_UNDO) {
ret.nFile = nFile;
Expand Down Expand Up @@ -284,21 +299,38 @@ class CBlockIndex

//! Check whether this block index entry is valid up to the passed validity level.
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
if (nStatus & BLOCK_FAILED_MASK)
return false;
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)
bool RaiseValidity(enum BlockStatus nUpTo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
if (nStatus & BLOCK_FAILED_MASK)
return false;
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;
}
Expand Down Expand Up @@ -339,6 +371,7 @@ class CDiskBlockIndex : public CBlockIndex

SERIALIZE_METHODS(CDiskBlockIndex, obj)
{
LOCK(::cs_main);
int _nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT_MODE(_nVersion, VarIntMode::NONNEGATIVE_SIGNED));

Expand Down
2 changes: 1 addition & 1 deletion src/index/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ bool BaseIndex::Init()
if (locator.IsNull()) {
m_best_block_index = nullptr;
} else {
m_best_block_index = m_chainstate->m_blockman.FindForkInGlobalIndex(active_chain, locator);
m_best_block_index = m_chainstate->FindForkInGlobalIndex(locator);
}

// Note: this will latch to true immediately if the user starts up with an empty
Expand Down
2 changes: 1 addition & 1 deletion src/index/coinstatsindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n

{
LOCK(cs_main);
CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
const auto& consensus_params{Params().GetConsensus()};

do {
Expand Down
7 changes: 5 additions & 2 deletions src/index/txindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <index/disktxpos.h>
#include <index/txindex.h>
#include <node/blockstorage.h>
#include <node/ui_interface.h>
#include <shutdown.h>
#include <util/system.h>
Expand Down Expand Up @@ -203,7 +204,7 @@ bool TxIndex::Init()
// Attempt to migrate txindex from the old database to the new one. Even if
// chain_tip is null, the node could be reindexing and we still want to
// delete txindex records in the old database.
if (!m_db->MigrateData(*pblocktree, m_chainstate->m_chain.GetLocator())) {
if (!m_db->MigrateData(*m_chainstate->m_blockman.m_block_tree_db, m_chainstate->m_chain.GetLocator())) {
return false;
}

Expand All @@ -215,7 +216,9 @@ bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
// Exclude genesis block transaction because outputs are not spendable.
if (pindex->nHeight == 0) return true;

CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
CDiskTxPos pos{
WITH_LOCK(::cs_main, return pindex->GetBlockPos()),
GetSizeOfCompactSize(block.vtx.size())};
std::vector<std::pair<uint256, CDiskTxPos>> vPos;
vPos.reserve(block.vtx.size());
for (const auto& tx : block.vtx) {
Expand Down
43 changes: 1 addition & 42 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ void PrepareShutdown(NodeContext& node)
chainstate->ResetCoinsViews();
}
}
pblocktree.reset();
node.chain_helper.reset();
if (node.mnhf_manager) {
node.mnhf_manager->DisconnectManagers();
Expand Down Expand Up @@ -831,47 +830,6 @@ static void BlockNotifyGenesisWait(const CBlockIndex* pBlockIndex)
}
}

// If we're using -prune with -reindex, then delete block files that will be ignored by the
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
// is missing, do the same here to delete any later block files after a gap. Also delete all
// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile
// is in sync with what's actually on disk by the time we start downloading, so that pruning
// works correctly.
static void CleanupBlockRevFiles()
{
std::map<std::string, fs::path> mapBlockFiles;

// Glob all blk?????.dat and rev?????.dat files from the blocks directory.
// Remove the rev files immediately and insert the blk file paths into an
// ordered map keyed by block file index.
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
fs::path blocksdir = gArgs.GetBlocksDirPath();
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
if (fs::is_regular_file(*it) &&
it->path().filename().string().length() == 12 &&
it->path().filename().string().substr(8,4) == ".dat")
{
if (it->path().filename().string().substr(0,3) == "blk")
mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();
else if (it->path().filename().string().substr(0,3) == "rev")
remove(it->path());
}
}

// Remove all block files that aren't part of a contiguous set starting at
// zero by walking the ordered map (keys are block file indices) by
// keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
// start removing block files.
int nContigCounter = 0;
for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {
nContigCounter++;
continue;
}
remove(item.second);
}
}

#if HAVE_SYSTEM
static void StartupNotify(const ArgsManager& args)
{
Expand Down Expand Up @@ -1992,6 +1950,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc

UnloadBlockIndex(node.mempool.get(), chainman);

auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
Expand Down
1 change: 1 addition & 0 deletions src/llmq/instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <index/txindex.h>
#include <masternode/sync.h>
#include <net_processing.h>
#include <node/blockstorage.h>
#include <spork.h>
#include <txmempool.h>
#include <util/irange.h>
Expand Down
3 changes: 2 additions & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}

BlockAssembler::Options::Options() {
BlockAssembler::Options::Options()
{
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
}
Expand Down
4 changes: 2 additions & 2 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3934,7 +3934,7 @@ void PeerManagerImpl::ProcessMessage(
LOCK(cs_main);

// Find the last block the caller has in the main chain
const CBlockIndex* pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
const CBlockIndex* pindex = m_chainman.ActiveChainstate().FindForkInGlobalIndex(locator);

// Send the rest of the chain
if (pindex)
Expand Down Expand Up @@ -4054,7 +4054,7 @@ void PeerManagerImpl::ProcessMessage(
else
{
// Find the last block the caller has in the main chain
pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
pindex = m_chainman.ActiveChainstate().FindForkInGlobalIndex(locator);
if (pindex)
pindex = m_chainman.ActiveChain().Next(pindex);
}
Expand Down
Loading
Loading