| 1349 | } |
| 1350 | |
| 1351 | bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool punish_duplicate_invalid) |
| 1352 | { |
| 1353 | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); |
| 1354 | size_t nCount = headers.size(); |
| 1355 | |
| 1356 | if (nCount == 0) { |
| 1357 | // Nothing interesting. Stop asking this peers for more headers. |
| 1358 | return true; |
| 1359 | } |
| 1360 | |
| 1361 | bool received_new_header = false; |
| 1362 | const CBlockIndex *pindexLast = nullptr; |
| 1363 | { |
| 1364 | LOCK(cs_main); |
| 1365 | CNodeState *nodestate = State(pfrom->GetId()); |
| 1366 | |
| 1367 | // If this looks like it could be a block announcement (nCount < |
| 1368 | // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that |
| 1369 | // don't connect: |
| 1370 | // - Send a getheaders message in response to try to connect the chain. |
| 1371 | // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that |
| 1372 | // don't connect before giving DoS points |
| 1373 | // - Once a headers message is received that is valid and does connect, |
| 1374 | // nUnconnectingHeaders gets reset back to 0. |
| 1375 | if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { |
| 1376 | nodestate->nUnconnectingHeaders++; |
| 1377 | connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); |
| 1378 | LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", |
| 1379 | headers[0].GetHash().ToString(), |
| 1380 | headers[0].hashPrevBlock.ToString(), |
| 1381 | pindexBestHeader->nHeight, |
| 1382 | pfrom->GetId(), nodestate->nUnconnectingHeaders); |
| 1383 | // Set hashLastUnknownBlock for this peer, so that if we |
| 1384 | // eventually get the headers - even from a different peer - |
| 1385 | // we can use this peer to download. |
| 1386 | UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash()); |
| 1387 | |
| 1388 | if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) { |
| 1389 | Misbehaving(pfrom->GetId(), 20); |
| 1390 | } |
| 1391 | return true; |
| 1392 | } |
| 1393 | |
| 1394 | uint256 hashLastBlock; |
| 1395 | for (const CBlockHeader& header : headers) { |
| 1396 | if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) { |
| 1397 | Misbehaving(pfrom->GetId(), 20, "non-continuous headers sequence"); |
| 1398 | return false; |
| 1399 | } |
| 1400 | hashLastBlock = header.GetHash(); |
| 1401 | } |
| 1402 | |
| 1403 | // If we don't have the last header, then they'll have given us |
| 1404 | // something new (if these headers are valid). |
| 1405 | if (!LookupBlockIndex(hashLastBlock)) { |
| 1406 | received_new_header = true; |
| 1407 | } |
| 1408 | } |
no test coverage detected