Skip to content

Commit b73d3bb

Browse files
sdaftuarryanofskyjamesob
committed
net_processing: Request assumeutxo background chain blocks
Add new PeerManagerImpl::TryDownloadingHistoricalBlocks method and use it to request background chain blocks in addition to blocks normally requested by FindNextBlocksToDownload. Co-authored-by: Ryan Ofsky <[email protected]> Co-authored-by: James O'Beirne <[email protected]>
1 parent 5bbf735 commit b73d3bb

File tree

3 files changed

+105
-8
lines changed

3 files changed

+105
-8
lines changed

src/net_processing.cpp

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,38 @@ class PeerManagerImpl final : public PeerManager
892892
*/
893893
void FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
894894

895+
/** Request blocks for the background chainstate, if one is in use. */
896+
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);
897+
898+
/**
899+
* \brief Find next blocks to download from a peer after a starting block.
900+
*
901+
* \param vBlocks Vector of blocks to download which will be appended to.
902+
* \param peer Peer which blocks will be downloaded from.
903+
* \param state Pointer to the state of the peer.
904+
* \param pindexWalk Pointer to the starting block to add to vBlocks.
905+
* \param count Maximum number of blocks to allow in vBlocks. No more
906+
* blocks will be added if it reaches this size.
907+
* \param nWindowEnd Maximum height of blocks to allow in vBlocks. No
908+
* blocks will be added above this height.
909+
* \param activeChain Optional pointer to a chain to compare against. If
910+
* provided, any next blocks which are already contained
911+
* in this chain will not be appended to vBlocks, but
912+
* instead will be used to update the
913+
* state->pindexLastCommonBlock pointer.
914+
* \param nodeStaller Optional pointer to a NodeId variable that will receive
915+
* the ID of another peer that might be causing this peer
916+
* to stall. This is set to the ID of the peer which
917+
* first requested the first in-flight block in the
918+
* download window. It is only set if vBlocks is empty at
919+
* the end of this function call and if increasing
920+
* nWindowEnd by 1 would cause it to be non-empty (which
921+
* indicates the download might be stalled because every
922+
* block in the window is in flight and no other peer is
923+
* trying to download the next block).
924+
*/
925+
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);
926+
895927
/* Multimap used to preserve insertion order */
896928
typedef std::multimap<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
897929
BlockDownloadMap mapBlocksInFlight GUARDED_BY(cs_main);
@@ -1312,6 +1344,7 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
13121344
}
13131345
}
13141346

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

1344-
std::vector<const CBlockIndex*> vToFetch;
13451377
const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
13461378
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
13471379
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
13481380
// download that next block if the window were 1 larger.
13491381
int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
1382+
1383+
FindNextBlocks(vBlocks, peer, state, pindexWalk, count, nWindowEnd, &m_chainman.ActiveChain(), &nodeStaller);
1384+
}
1385+
1386+
void PeerManagerImpl::TryDownloadingHistoricalBlocks(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex *from_tip, const CBlockIndex* target_block)
1387+
{
1388+
Assert(from_tip);
1389+
Assert(target_block);
1390+
1391+
if (vBlocks.size() >= count) {
1392+
return;
1393+
}
1394+
1395+
vBlocks.reserve(count);
1396+
CNodeState *state = Assert(State(peer.m_id));
1397+
1398+
if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->GetAncestor(target_block->nHeight) != target_block) {
1399+
// This peer can't provide us the complete series of blocks leading up to the
1400+
// assumeutxo snapshot base.
1401+
//
1402+
// Presumably this peer's chain has less work than our ActiveChain()'s tip, or else we
1403+
// will eventually crash when we try to reorg to it. Let other logic
1404+
// deal with whether we disconnect this peer.
1405+
//
1406+
// TODO at some point in the future, we might choose to request what blocks
1407+
// this peer does have from the historical chain, despite it not having a
1408+
// complete history beneath the snapshot base.
1409+
return;
1410+
}
1411+
1412+
FindNextBlocks(vBlocks, peer, state, from_tip, count, std::min<int>(from_tip->nHeight + BLOCK_DOWNLOAD_WINDOW, target_block->nHeight));
1413+
}
1414+
1415+
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)
1416+
{
1417+
std::vector<const CBlockIndex*> vToFetch;
13501418
int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
13511419
NodeId waitingfor = -1;
13521420
while (pindexWalk->nHeight < nMaxHeight) {
@@ -1374,16 +1442,16 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
13741442
// We wouldn't download this block or its descendants from this peer.
13751443
return;
13761444
}
1377-
if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) {
1378-
if (pindex->HaveTxsDownloaded())
1445+
if (pindex->nStatus & BLOCK_HAVE_DATA || (activeChain && activeChain->Contains(pindex))) {
1446+
if (activeChain && pindex->HaveTxsDownloaded())
13791447
state->pindexLastCommonBlock = pindex;
13801448
} else if (!IsBlockRequested(pindex->GetBlockHash())) {
13811449
// The block is not already downloaded, and not yet in flight.
13821450
if (pindex->nHeight > nWindowEnd) {
13831451
// We reached the end of the window.
13841452
if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
13851453
// We aren't able to fetch anything, but we would be if the download window was one larger.
1386-
nodeStaller = waitingfor;
1454+
if (nodeStaller) *nodeStaller = waitingfor;
13871455
}
13881456
return;
13891457
}
@@ -5847,7 +5915,20 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
58475915
if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.IsInitialBlockDownload()) && state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
58485916
std::vector<const CBlockIndex*> vToDownload;
58495917
NodeId staller = -1;
5850-
FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.vBlocksInFlight.size(), vToDownload, staller);
5918+
auto get_inflight_budget = [&state]() {
5919+
return std::max(0, MAX_BLOCKS_IN_TRANSIT_PER_PEER - static_cast<int>(state.vBlocksInFlight.size()));
5920+
};
5921+
5922+
// If a snapshot chainstate is in use, we want to find its next blocks
5923+
// before the background chainstate to prioritize getting to network tip.
5924+
FindNextBlocksToDownload(*peer, get_inflight_budget(), vToDownload, staller);
5925+
if (m_chainman.BackgroundSyncInProgress() && !IsLimitedPeer(*peer)) {
5926+
TryDownloadingHistoricalBlocks(
5927+
*peer,
5928+
get_inflight_budget(),
5929+
vToDownload, m_chainman.GetBackgroundSyncTip(),
5930+
Assert(m_chainman.GetSnapshotBaseBlock()));
5931+
}
58515932
for (const CBlockIndex *pindex : vToDownload) {
58525933
uint32_t nFetchFlags = GetFetchFlags(*peer);
58535934
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));

src/validation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4148,6 +4148,12 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo
41484148
return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString());
41494149
}
41504150

4151+
Chainstate* bg_chain{WITH_LOCK(cs_main, return BackgroundSyncInProgress() ? m_ibd_chainstate.get() : nullptr)};
4152+
BlockValidationState bg_state;
4153+
if (bg_chain && !bg_chain->ActivateBestChain(bg_state, block)) {
4154+
return error("%s: [background] ActivateBestChain failed (%s)", __func__, bg_state.ToString());
4155+
}
4156+
41514157
return true;
41524158
}
41534159

src/validation.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -881,9 +881,6 @@ class ChainstateManager
881881
/** Most recent headers presync progress update, for rate-limiting. */
882882
std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {};
883883

884-
//! Returns nullptr if no snapshot has been loaded.
885-
const CBlockIndex* GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
886-
887884
//! Return the height of the base block of the snapshot in use, if one exists, else
888885
//! nullopt.
889886
std::optional<int> GetSnapshotBaseHeight() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
@@ -1034,12 +1031,25 @@ class ChainstateManager
10341031
//! Otherwise, revert to using the ibd chainstate and shutdown.
10351032
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
10361033

1034+
//! Returns nullptr if no snapshot has been loaded.
1035+
const CBlockIndex* GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
1036+
10371037
//! The most-work chain.
10381038
Chainstate& ActiveChainstate() const;
10391039
CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; }
10401040
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); }
10411041
CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); }
10421042

1043+
//! The state of a background sync (for net processing)
1044+
bool BackgroundSyncInProgress() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) {
1045+
return IsUsable(m_snapshot_chainstate.get()) && IsUsable(m_ibd_chainstate.get());
1046+
}
1047+
1048+
//! The tip of the background sync chain
1049+
const CBlockIndex* GetBackgroundSyncTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) {
1050+
return BackgroundSyncInProgress() ? m_ibd_chainstate->m_chain.Tip() : nullptr;
1051+
}
1052+
10431053
node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
10441054
{
10451055
AssertLockHeld(::cs_main);

0 commit comments

Comments
 (0)