diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -888,6 +888,11 @@ /** Request further headers from this peer from a given block header */ void FetchMoreHeaders(CNode &pfrom, const CBlockIndex *pindexLast, const Peer &peer) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + /** + * Potentially fetch blocks from this peer upon receipt of new headers tip + */ + void HeadersDirectFetchBlocks(const Config &config, CNode &pfrom, + const CBlockIndex *pindexLast); void SendBlockTransactions(CNode &pfrom, Peer &peer, const CBlock &block, const BlockTransactionsRequest &req); @@ -3273,6 +3278,80 @@ uint256())); } +/** + * Given a new headers tip ending in pindexLast, potentially request blocks + * towards that tip. We require that the given tip have at least as much work as + * our tip, and for our current tip to be "close to synced" (see + * CanDirectFetch()). + */ +void PeerManagerImpl::HeadersDirectFetchBlocks(const Config &config, + CNode &pfrom, + const CBlockIndex *pindexLast) { + const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); + + LOCK(cs_main); + CNodeState *nodestate = State(pfrom.GetId()); + + if (CanDirectFetch() && pindexLast->IsValid(BlockValidity::TREE) && + m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) { + std::vector<const CBlockIndex *> vToFetch; + const CBlockIndex *pindexWalk = pindexLast; + // Calculate all the blocks we'd need to switch to pindexLast, up to + // a limit. + while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && + vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pindexWalk->nStatus.hasData() && + !IsBlockRequested(pindexWalk->GetBlockHash())) { + // We don't have this block, and it's not yet in flight. + vToFetch.push_back(pindexWalk); + } + pindexWalk = pindexWalk->pprev; + } + // If pindexWalk still isn't on our main chain, we're looking at a + // very large reorg at a time we think we're close to caught up to + // the main chain -- this shouldn't really happen. Bail out on the + // direct fetch and rely on parallel download instead. + if (!m_chainman.ActiveChain().Contains(pindexWalk)) { + LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", + pindexLast->GetBlockHash().ToString(), + pindexLast->nHeight); + } else { + std::vector<CInv> vGetData; + // Download as much as possible, from earliest to latest. + for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { + if (nodestate->nBlocksInFlight >= + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + // Can't download any more from this peer + break; + } + vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); + BlockRequested(config, pfrom.GetId(), *pindex); + LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", + pindex->GetBlockHash().ToString(), pfrom.GetId()); + } + if (vGetData.size() > 1) { + LogPrint(BCLog::NET, + "Downloading blocks toward %s (%d) via headers " + "direct fetch\n", + pindexLast->GetBlockHash().ToString(), + pindexLast->nHeight); + } + if (vGetData.size() > 0) { + if (!m_ignore_incoming_txs && + nodestate->m_provides_cmpctblocks && vGetData.size() == 1 && + mapBlocksInFlight.size() == 1 && + pindexLast->pprev->IsValid(BlockValidity::CHAIN)) { + // In any case, we want to download using a compact + // block, not a regular one. + vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); + } + m_connman.PushMessage( + &pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + } + } + } +} + void PeerManagerImpl::ProcessHeadersMessage( const Config &config, CNode &pfrom, Peer &peer, const std::vector<CBlockHeader> &headers, bool via_compact_block) { @@ -3361,68 +3440,6 @@ nodestate->m_last_block_announcement = GetTime(); } - // If this set of headers is valid and ends in a block with at least as - // much work as our tip, download as much as possible. - if (CanDirectFetch() && pindexLast->IsValid(BlockValidity::TREE) && - m_chainman.ActiveChain().Tip()->nChainWork <= - pindexLast->nChainWork) { - std::vector<const CBlockIndex *> vToFetch; - const CBlockIndex *pindexWalk = pindexLast; - // Calculate all the blocks we'd need to switch to pindexLast, up to - // a limit. - while (pindexWalk && - !m_chainman.ActiveChain().Contains(pindexWalk) && - vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - if (!pindexWalk->nStatus.hasData() && - !IsBlockRequested(pindexWalk->GetBlockHash())) { - // We don't have this block, and it's not yet in flight. - vToFetch.push_back(pindexWalk); - } - pindexWalk = pindexWalk->pprev; - } - // If pindexWalk still isn't on our main chain, we're looking at a - // very large reorg at a time we think we're close to caught up to - // the main chain -- this shouldn't really happen. Bail out on the - // direct fetch and rely on parallel download instead. - if (!m_chainman.ActiveChain().Contains(pindexWalk)) { - LogPrint( - BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", - pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); - } else { - std::vector<CInv> vGetData; - // Download as much as possible, from earliest to latest. - for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { - if (nodestate->nBlocksInFlight >= - MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - // Can't download any more from this peer - break; - } - vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); - BlockRequested(config, pfrom.GetId(), *pindex); - LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", - pindex->GetBlockHash().ToString(), pfrom.GetId()); - } - if (vGetData.size() > 1) { - LogPrint(BCLog::NET, - "Downloading blocks toward %s (%d) via headers " - "direct fetch\n", - pindexLast->GetBlockHash().ToString(), - pindexLast->nHeight); - } - if (vGetData.size() > 0) { - if (!m_ignore_incoming_txs && - nodestate->m_provides_cmpctblocks && - vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && - pindexLast->pprev->IsValid(BlockValidity::CHAIN)) { - // In any case, we want to download using a compact - // block, not a regular one. - vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); - } - m_connman.PushMessage( - &pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData)); - } - } - } // If we're in IBD, we want outbound peers that will serve us a useful // chain. Disconnect peers that are on chains with insufficient work. if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && @@ -3470,6 +3487,9 @@ } } } + + // Consider immediately downloading blocks. + HeadersDirectFetchBlocks(config, pfrom, pindexLast); } /**