* 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()). */
| 2870 | * our current tip to be "close to synced" (see CanDirectFetch()). |
| 2871 | */ |
| 2872 | void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header) |
| 2873 | { |
| 2874 | LOCK(cs_main); |
| 2875 | CNodeState *nodestate = State(pfrom.GetId()); |
| 2876 | |
| 2877 | if (CanDirectFetch() && last_header.IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= last_header.nChainWork) { |
| 2878 | std::vector<const CBlockIndex*> vToFetch; |
| 2879 | const CBlockIndex* pindexWalk{&last_header}; |
| 2880 | // Calculate all the blocks we'd need to switch to last_header, up to a limit. |
| 2881 | while (pindexWalk && !m_chainman.ActiveChain().Contains(*pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
| 2882 | if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && |
| 2883 | !IsBlockRequested(pindexWalk->GetBlockHash()) && |
| 2884 | (!DeploymentActiveAt(*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || CanServeWitnesses(peer))) { |
| 2885 | // We don't have this block, and it's not yet in flight. |
| 2886 | vToFetch.push_back(pindexWalk); |
| 2887 | } |
| 2888 | pindexWalk = pindexWalk->pprev; |
| 2889 | } |
| 2890 | // If pindexWalk still isn't on our main chain, we're looking at a |
| 2891 | // very large reorg at a time we think we're close to caught up to |
| 2892 | // the main chain -- this shouldn't really happen. Bail out on the |
| 2893 | // direct fetch and rely on parallel download instead. |
| 2894 | // Common ancestor must exist (genesis). |
| 2895 | if (!m_chainman.ActiveChain().Contains(*Assert(pindexWalk))) { |
| 2896 | LogDebug(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", |
| 2897 | last_header.GetBlockHash().ToString(), |
| 2898 | last_header.nHeight); |
| 2899 | } else { |
| 2900 | std::vector<CInv> vGetData; |
| 2901 | // Download as much as possible, from earliest to latest. |
| 2902 | for (const CBlockIndex* pindex : vToFetch | std::views::reverse) { |
| 2903 | if (nodestate->vBlocksInFlight.size() >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { |
| 2904 | // Can't download any more from this peer |
| 2905 | break; |
| 2906 | } |
| 2907 | uint32_t nFetchFlags = GetFetchFlags(peer); |
| 2908 | vGetData.emplace_back(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()); |
| 2909 | BlockRequested(pfrom.GetId(), *pindex); |
| 2910 | LogDebug(BCLog::NET, "Requesting block %s from peer=%d", |
| 2911 | pindex->GetBlockHash().ToString(), pfrom.GetId()); |
| 2912 | } |
| 2913 | if (vGetData.size() > 1) { |
| 2914 | LogDebug(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n", |
| 2915 | last_header.GetBlockHash().ToString(), |
| 2916 | last_header.nHeight); |
| 2917 | } |
| 2918 | if (vGetData.size() > 0) { |
| 2919 | if (!m_opts.ignore_incoming_txs && |
| 2920 | nodestate->m_provides_cmpctblocks && |
| 2921 | vGetData.size() == 1 && |
| 2922 | mapBlocksInFlight.size() == 1 && |
| 2923 | last_header.pprev->IsValid(BLOCK_VALID_CHAIN)) { |
| 2924 | // In any case, we want to download using a compact block, not a regular one |
| 2925 | vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash); |
| 2926 | } |
| 2927 | MakeAndPushMessage(pfrom, NetMsgType::GETDATA, vGetData); |
| 2928 | } |
| 2929 | } |
nothing calls this directly
no test coverage detected