* Given a new headers tip ending in last_header, 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()). */
| 3980 | * CanDirectFetch()). |
| 3981 | */ |
| 3982 | void PeerManagerImpl::HeadersDirectFetchBlocks(const Config &config, |
| 3983 | CNode &pfrom, |
| 3984 | const CBlockIndex &last_header) { |
| 3985 | LOCK(cs_main); |
| 3986 | CNodeState *nodestate = State(pfrom.GetId()); |
| 3987 | |
| 3988 | if (CanDirectFetch() && last_header.IsValid(BlockValidity::TREE) && |
| 3989 | m_chainman.ActiveChain().Tip()->nChainWork <= last_header.nChainWork) { |
| 3990 | std::vector<const CBlockIndex *> vToFetch; |
| 3991 | const CBlockIndex *pindexWalk{&last_header}; |
| 3992 | // Calculate all the blocks we'd need to switch to last_header, up to |
| 3993 | // a limit. |
| 3994 | while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && |
| 3995 | vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
| 3996 | if (!pindexWalk->nStatus.hasData() && |
| 3997 | !IsBlockRequested(pindexWalk->GetBlockHash())) { |
| 3998 | // We don't have this block, and it's not yet in flight. |
| 3999 | vToFetch.push_back(pindexWalk); |
| 4000 | } |
| 4001 | pindexWalk = pindexWalk->pprev; |
| 4002 | } |
| 4003 | // If pindexWalk still isn't on our main chain, we're looking at a |
| 4004 | // very large reorg at a time we think we're close to caught up to |
| 4005 | // the main chain -- this shouldn't really happen. Bail out on the |
| 4006 | // direct fetch and rely on parallel download instead. |
| 4007 | if (!m_chainman.ActiveChain().Contains(pindexWalk)) { |
| 4008 | LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", |
| 4009 | last_header.GetBlockHash().ToString(), |
| 4010 | last_header.nHeight); |
| 4011 | } else { |
| 4012 | std::vector<CInv> vGetData; |
| 4013 | // Download as much as possible, from earliest to latest. |
| 4014 | for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) { |
| 4015 | if (nodestate->vBlocksInFlight.size() >= |
| 4016 | MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
| 4017 | // Can't download any more from this peer |
| 4018 | break; |
| 4019 | } |
| 4020 | vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); |
| 4021 | BlockRequested(config, pfrom.GetId(), *pindex); |
| 4022 | LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", |
| 4023 | pindex->GetBlockHash().ToString(), pfrom.GetId()); |
| 4024 | } |
| 4025 | if (vGetData.size() > 1) { |
| 4026 | LogPrint(BCLog::NET, |
| 4027 | "Downloading blocks toward %s (%d) via headers " |
| 4028 | "direct fetch\n", |
| 4029 | last_header.GetBlockHash().ToString(), |
| 4030 | last_header.nHeight); |
| 4031 | } |
| 4032 | if (vGetData.size() > 0) { |
| 4033 | if (!m_opts.ignore_incoming_txs && |
| 4034 | nodestate->m_provides_cmpctblocks && vGetData.size() == 1 && |
| 4035 | mapBlocksInFlight.size() == 1 && |
| 4036 | last_header.pprev->IsValid(BlockValidity::CHAIN)) { |
| 4037 | // In any case, we want to download using a compact |
| 4038 | // block, not a regular one. |
| 4039 | vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); |
nothing calls this directly
no test coverage detected