@@ -560,6 +560,11 @@ class PeerManagerImpl final : public PeerManager
560
560
const std::vector<CBlockHeader>& headers,
561
561
bool via_compact_block)
562
562
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);
563
568
564
569
void SendBlockTransactions (CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
565
570
@@ -2194,6 +2199,48 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlo
2194
2199
m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::BLOCKTXN, resp));
2195
2200
}
2196
2201
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
+
2197
2244
void PeerManagerImpl::ProcessHeadersMessage (CNode& pfrom, Peer& peer,
2198
2245
const std::vector<CBlockHeader>& headers,
2199
2246
bool via_compact_block)
@@ -2208,36 +2255,24 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
2208
2255
2209
2256
bool received_new_header = false ;
2210
2257
const CBlockIndex *pindexLast = nullptr ;
2211
- {
2212
- LOCK (cs_main);
2213
- CNodeState *nodestate = State (pfrom.GetId ());
2214
2258
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" );
2240
2270
}
2271
+ return ;
2272
+ }
2273
+
2274
+ {
2275
+ LOCK (cs_main);
2241
2276
2242
2277
uint256 hashLastBlock;
2243
2278
for (const CBlockHeader& header : headers) {
0 commit comments