Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b73d3bb
net_processing: Request assumeutxo background chain blocks
sdaftuar May 4, 2023
c93ef43
bugfix: correct is_snapshot_cs in VerifyDB
jamesob May 25, 2023
c711ca1
assumeutxo: remove snapshot during -reindex{-chainstate}
jamesob May 3, 2023
434495a
chainparams: add blockhash to AssumeutxoData
jamesob May 25, 2023
9f2318c
validation: MaybeRebalanceCaches when chain leaves IBD
jamesob May 1, 2023
c6af23c
validation: add ChainstateRole
jamesob Nov 10, 2022
1e59acd
validation: only call UpdatedBlockTip for active chainstate
jamesob Aug 24, 2023
4d8f4dc
validation: pass ChainstateRole for validationinterface calls
jamesob Sep 23, 2019
f073917
validationinterface: only send zmq notifications for active
jamesob Nov 10, 2022
fbe0a7d
wallet: validationinterface: only handle active chain notifications
jamesob Nov 10, 2022
1fffdd7
net_processing: validationinterface: ignore some events for bg chain
jamesob Nov 10, 2022
373cf91
validation: indexing changes for assumeutxo
jamesob Sep 23, 2019
1019c39
validation: pruning for multiple chainstates
jamesob Sep 16, 2019
49ef778
test: adjust chainstate tests to use recognized snapshot base
jamesob Aug 25, 2023
4c3b8ca
validation: populate nChainTx value for assumedvalid chainstates
jamesob May 5, 2023
7fcd215
blockstorage: segment normal/assumedvalid blockfiles
jamesob May 3, 2023
9511fb3
validation: assumeutxo: swap m_mempool on snapshot activation
jamesob May 5, 2023
62ac519
validation: do not activate snapshot if behind active chain
jamesob Sep 17, 2023
ce585a9
rpc: add loadtxoutset
jamesob Mar 29, 2019
bb05857
refuse to activate a UTXO snapshot if mempool not empty
jamesob Sep 8, 2023
0f64bac
rpc: add getchainstates
jamesob Mar 29, 2019
42cae39
test: add feature_assumeutxo functional test
jamesob Jun 17, 2021
7ee46a7
contrib: add script to demo/test assumeutxo
jamesob Jun 16, 2021
99839bb
doc: add note about confusing HaveTxsDownloaded name
jamesob Sep 11, 2023
b8cafe3
chainparams: add testnet assumeutxo param at height 2_500_000
Sjors Sep 21, 2023
edbed31
chainparams: add signet assumeutxo param at height 160_000
Sjors Sep 21, 2023
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
91 changes: 86 additions & 5 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,38 @@ class PeerManagerImpl final : public PeerManager
*/
void FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

/** Request blocks for the background chainstate, if one is in use. */
void TryDownloadingHistoricalBlocks(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex* from_tip, const CBlockIndex* target_block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
Comment thread
jamesob marked this conversation as resolved.

/**
* \brief Find next blocks to download from a peer after a starting block.
*
* \param vBlocks Vector of blocks to download which will be appended to.
* \param peer Peer which blocks will be downloaded from.
* \param state Pointer to the state of the peer.
* \param pindexWalk Pointer to the starting block to add to vBlocks.
* \param count Maximum number of blocks to allow in vBlocks. No more
* blocks will be added if it reaches this size.
* \param nWindowEnd Maximum height of blocks to allow in vBlocks. No
* blocks will be added above this height.
* \param activeChain Optional pointer to a chain to compare against. If
* provided, any next blocks which are already contained
* in this chain will not be appended to vBlocks, but
* instead will be used to update the
* state->pindexLastCommonBlock pointer.
* \param nodeStaller Optional pointer to a NodeId variable that will receive
* the ID of another peer that might be causing this peer
* to stall. This is set to the ID of the peer which
* first requested the first in-flight block in the
* download window. It is only set if vBlocks is empty at
* the end of this function call and if increasing
* nWindowEnd by 1 would cause it to be non-empty (which
* indicates the download might be stalled because every
* block in the window is in flight and no other peer is
* trying to download the next block).
*/
void FindNextBlocks(std::vector<const CBlockIndex*>& vBlocks, const Peer& peer, CNodeState *state, const CBlockIndex *pindexWalk, unsigned int count, int nWindowEnd, const CChain* activeChain=nullptr, NodeId* nodeStaller=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

/* Multimap used to preserve insertion order */
typedef std::multimap<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
BlockDownloadMap mapBlocksInFlight GUARDED_BY(cs_main);
Expand Down Expand Up @@ -1312,6 +1344,7 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
}
}

// Logic for calculating which blocks to download from a given peer, given our current tip.
void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
{
if (count == 0)
Expand Down Expand Up @@ -1341,12 +1374,47 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
return;

std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
// download that next block if the window were 1 larger.
int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;

FindNextBlocks(vBlocks, peer, state, pindexWalk, count, nWindowEnd, &m_chainman.ActiveChain(), &nodeStaller);
}

void PeerManagerImpl::TryDownloadingHistoricalBlocks(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex *from_tip, const CBlockIndex* target_block)
Comment thread
jamesob marked this conversation as resolved.
Outdated
Comment thread
jamesob marked this conversation as resolved.
{
Assert(from_tip);
Assert(target_block);

if (vBlocks.size() >= count) {
return;
}

vBlocks.reserve(count);
CNodeState *state = Assert(State(peer.m_id));

if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->GetAncestor(target_block->nHeight) != target_block) {
// This peer can't provide us the complete series of blocks leading up to the
// assumeutxo snapshot base.
//
// Presumably this peer's chain has less work than our ActiveChain()'s tip, or else we
// will eventually crash when we try to reorg to it. Let other logic
// deal with whether we disconnect this peer.
//
// TODO at some point in the future, we might choose to request what blocks
// this peer does have from the historical chain, despite it not having a
// complete history beneath the snapshot base.
Comment thread
jamesob marked this conversation as resolved.
return;
}

FindNextBlocks(vBlocks, peer, state, from_tip, count, std::min<int>(from_tip->nHeight + BLOCK_DOWNLOAD_WINDOW, target_block->nHeight));
}

void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex*>& vBlocks, const Peer& peer, CNodeState *state, const CBlockIndex *pindexWalk, unsigned int count, int nWindowEnd, const CChain* activeChain, NodeId* nodeStaller)
{
std::vector<const CBlockIndex*> vToFetch;
int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
NodeId waitingfor = -1;
while (pindexWalk->nHeight < nMaxHeight) {
Expand Down Expand Up @@ -1374,16 +1442,16 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
// We wouldn't download this block or its descendants from this peer.
return;
}
if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) {
if (pindex->HaveTxsDownloaded())
if (pindex->nStatus & BLOCK_HAVE_DATA || (activeChain && activeChain->Contains(pindex))) {
if (activeChain && pindex->HaveTxsDownloaded())
state->pindexLastCommonBlock = pindex;
} else if (!IsBlockRequested(pindex->GetBlockHash())) {
// The block is not already downloaded, and not yet in flight.
if (pindex->nHeight > nWindowEnd) {
// We reached the end of the window.
if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
// We aren't able to fetch anything, but we would be if the download window was one larger.
nodeStaller = waitingfor;
if (nodeStaller) *nodeStaller = waitingfor;
}
return;
}
Expand Down Expand Up @@ -5847,7 +5915,20 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.IsInitialBlockDownload()) && state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.vBlocksInFlight.size(), vToDownload, staller);
auto get_inflight_budget = [&state]() {
return std::max(0, MAX_BLOCKS_IN_TRANSIT_PER_PEER - static_cast<int>(state.vBlocksInFlight.size()));
};

// If a snapshot chainstate is in use, we want to find its next blocks
// before the background chainstate to prioritize getting to network tip.
FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload, staller);
Comment thread
jamesob marked this conversation as resolved.
if (m_chainman.BackgroundSyncInProgress() && !IsLimitedPeer(*peer)) {
TryDownloadingHistoricalBlocks(
*peer,
get_inflight_budget(),
vToDownload, m_chainman.GetBackgroundSyncTip(),
Assert(m_chainman.GetSnapshotBaseBlock()));
}
for (const CBlockIndex *pindex : vToDownload) {
uint32_t nFetchFlags = GetFetchFlags(*peer);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
Expand Down
6 changes: 6 additions & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4148,6 +4148,12 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo
return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString());
}

Chainstate* bg_chain{WITH_LOCK(cs_main, return BackgroundSyncInProgress() ? m_ibd_chainstate.get() : nullptr)};
BlockValidationState bg_state;
if (bg_chain && !bg_chain->ActivateBestChain(bg_state, block)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a9ea542: it's probably not significant, but if we split up the two ifs we could avoid creating bg_state object each time a new block comes in when not using AssumeUtxo.

return error("%s: [background] ActivateBestChain failed (%s)", __func__, bg_state.ToString());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could adapt the error above to also include the name of the chainstate.

}

return true;
}

Expand Down
16 changes: 13 additions & 3 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,9 +881,6 @@ class ChainstateManager
/** Most recent headers presync progress update, for rate-limiting. */
std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {};

//! Returns nullptr if no snapshot has been loaded.
const CBlockIndex* GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);

//! Return the height of the base block of the snapshot in use, if one exists, else
//! nullopt.
std::optional<int> GetSnapshotBaseHeight() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
Expand Down Expand Up @@ -1034,12 +1031,25 @@ class ChainstateManager
//! Otherwise, revert to using the ibd chainstate and shutdown.
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);

//! Returns nullptr if no snapshot has been loaded.
const CBlockIndex* GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
Comment thread
jamesob marked this conversation as resolved.

//! The most-work chain.
Chainstate& ActiveChainstate() const;
CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; }
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); }
CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); }

//! The state of a background sync (for net processing)
bool BackgroundSyncInProgress() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) {
return IsUsable(m_snapshot_chainstate.get()) && IsUsable(m_ibd_chainstate.get());
Comment thread
jamesob marked this conversation as resolved.
}

//! The tip of the background sync chain
const CBlockIndex* GetBackgroundSyncTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) {
return BackgroundSyncInProgress() ? m_ibd_chainstate->m_chain.Tip() : nullptr;
}

node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
Expand Down