Skip to content

Commit 7f24508

Browse files
committed
Move handling of unconnecting headers into own function
1 parent 2111f32 commit 7f24508

File tree

1 file changed

+63
-28
lines changed

1 file changed

+63
-28
lines changed

src/net_processing.cpp

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,11 @@ class PeerManagerImpl final : public PeerManager
560560
const std::vector<CBlockHeader>& headers,
561561
bool via_compact_block)
562562
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
563+
/** Various helpers for headers processing, invoked by ProcessHeadersMessage() */
564+
/** Deal with state tracking and headers sync for peers that send the
565+
* occasional non-connecting header (this can happen due to BIP 130 headers
566+
* announcements for blocks interacting with the 2hr (MAX_FUTURE_BLOCK_TIME) rule). */
567+
void HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer, const std::vector<CBlockHeader>& headers);
563568

564569
void SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
565570

@@ -2194,6 +2199,48 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlo
21942199
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCKTXN, resp));
21952200
}
21962201

2202+
/**
2203+
* Special handling for unconnecting headers that might be part of a block
2204+
* announcement.
2205+
*
2206+
* We'll send a getheaders message in response to try to connect the chain.
2207+
*
2208+
* The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
2209+
* don't connect before given DoS points.
2210+
*
2211+
* Once a headers message is received that is valid and does connect,
2212+
* nUnconnectingHeaders gets reset back to 0.
2213+
*/
2214+
void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
2215+
const std::vector<CBlockHeader>& headers)
2216+
{
2217+
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
2218+
2219+
LOCK(cs_main);
2220+
CNodeState *nodestate = State(pfrom.GetId());
2221+
2222+
nodestate->nUnconnectingHeaders++;
2223+
2224+
// Try to fill in the missing headers.
2225+
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
2226+
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
2227+
headers[0].GetHash().ToString(),
2228+
headers[0].hashPrevBlock.ToString(),
2229+
m_chainman.m_best_header->nHeight,
2230+
pfrom.GetId(), nodestate->nUnconnectingHeaders);
2231+
2232+
// Set hashLastUnknownBlock for this peer, so that if we
2233+
// eventually get the headers - even from a different peer -
2234+
// we can use this peer to download.
2235+
UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash());
2236+
2237+
// The peer may just be broken, so periodically assign DoS points if this
2238+
// condition persists.
2239+
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
2240+
Misbehaving(peer, 20, strprintf("%d non-connecting headers", nodestate->nUnconnectingHeaders));
2241+
}
2242+
}
2243+
21972244
void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
21982245
const std::vector<CBlockHeader>& headers,
21992246
bool via_compact_block)
@@ -2208,36 +2255,24 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
22082255

22092256
bool received_new_header = false;
22102257
const CBlockIndex *pindexLast = nullptr;
2211-
{
2212-
LOCK(cs_main);
2213-
CNodeState *nodestate = State(pfrom.GetId());
22142258

2215-
// If this looks like it could be a block announcement (nCount <=
2216-
// MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
2217-
// don't connect:
2218-
// - Send a getheaders message in response to try to connect the chain.
2219-
// - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
2220-
// don't connect before giving DoS points
2221-
// - Once a headers message is received that is valid and does connect,
2222-
// nUnconnectingHeaders gets reset back to 0.
2223-
if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount <= MAX_BLOCKS_TO_ANNOUNCE) {
2224-
nodestate->nUnconnectingHeaders++;
2225-
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), uint256()));
2226-
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
2227-
headers[0].GetHash().ToString(),
2228-
headers[0].hashPrevBlock.ToString(),
2229-
m_chainman.m_best_header->nHeight,
2230-
pfrom.GetId(), nodestate->nUnconnectingHeaders);
2231-
// Set hashLastUnknownBlock for this peer, so that if we
2232-
// eventually get the headers - even from a different peer -
2233-
// we can use this peer to download.
2234-
UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash());
2235-
2236-
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
2237-
Misbehaving(peer, 20, strprintf("%d non-connecting headers", nodestate->nUnconnectingHeaders));
2238-
}
2239-
return;
2259+
// Do these headers connect to something in our block index?
2260+
bool headers_connect_blockindex{WITH_LOCK(::cs_main, return m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) != nullptr)};
2261+
2262+
if (!headers_connect_blockindex) {
2263+
if (nCount <= MAX_BLOCKS_TO_ANNOUNCE) {
2264+
// If this looks like it could be a BIP 130 block announcement, use
2265+
// special logic for handling headers that don't connect, as this
2266+
// could be benign.
2267+
HandleFewUnconnectingHeaders(pfrom, peer, headers);
2268+
} else {
2269+
Misbehaving(peer, 10, "invalid header received");
22402270
}
2271+
return;
2272+
}
2273+
2274+
{
2275+
LOCK(cs_main);
22412276

22422277
uint256 hashLastBlock;
22432278
for (const CBlockHeader& header : headers) {

0 commit comments

Comments
 (0)