@@ -1205,6 +1205,178 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
12051205 connman->PushMessage (pfrom, msgMaker.Make (nSendFlags, NetMsgType::BLOCKTXN, resp));
12061206}
12071207
1208+ bool static ProcessHeadersMessage (CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams)
1209+ {
1210+ const CNetMsgMaker msgMaker (pfrom->GetSendVersion ());
1211+ size_t nCount = headers.size ();
1212+
1213+ if (nCount == 0 ) {
1214+ // Nothing interesting. Stop asking this peers for more headers.
1215+ return true ;
1216+ }
1217+
1218+ const CBlockIndex *pindexLast = nullptr ;
1219+ {
1220+ LOCK (cs_main);
1221+ CNodeState *nodestate = State (pfrom->GetId ());
1222+
1223+ // If this looks like it could be a block announcement (nCount <
1224+ // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
1225+ // don't connect:
1226+ // - Send a getheaders message in response to try to connect the chain.
1227+ // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
1228+ // don't connect before giving DoS points
1229+ // - Once a headers message is received that is valid and does connect,
1230+ // nUnconnectingHeaders gets reset back to 0.
1231+ if (mapBlockIndex.find (headers[0 ].hashPrevBlock ) == mapBlockIndex.end () && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
1232+ nodestate->nUnconnectingHeaders ++;
1233+ connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETHEADERS, chainActive.GetLocator (pindexBestHeader), uint256 ()));
1234+ LogPrint (BCLog::NET, " received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n " ,
1235+ headers[0 ].GetHash ().ToString (),
1236+ headers[0 ].hashPrevBlock .ToString (),
1237+ pindexBestHeader->nHeight ,
1238+ pfrom->GetId (), nodestate->nUnconnectingHeaders );
1239+ // Set hashLastUnknownBlock for this peer, so that if we
1240+ // eventually get the headers - even from a different peer -
1241+ // we can use this peer to download.
1242+ UpdateBlockAvailability (pfrom->GetId (), headers.back ().GetHash ());
1243+
1244+ if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0 ) {
1245+ Misbehaving (pfrom->GetId (), 20 );
1246+ }
1247+ return true ;
1248+ }
1249+
1250+ uint256 hashLastBlock;
1251+ for (const CBlockHeader& header : headers) {
1252+ if (!hashLastBlock.IsNull () && header.hashPrevBlock != hashLastBlock) {
1253+ Misbehaving (pfrom->GetId (), 20 );
1254+ return error (" non-continuous headers sequence" );
1255+ }
1256+ hashLastBlock = header.GetHash ();
1257+ }
1258+ }
1259+
1260+ CValidationState state;
1261+ if (!ProcessNewBlockHeaders (headers, state, chainparams, &pindexLast)) {
1262+ int nDoS;
1263+ if (state.IsInvalid (nDoS)) {
1264+ if (nDoS > 0 ) {
1265+ LOCK (cs_main);
1266+ Misbehaving (pfrom->GetId (), nDoS);
1267+ }
1268+ return error (" invalid header received" );
1269+ }
1270+ }
1271+
1272+ {
1273+ LOCK (cs_main);
1274+ CNodeState *nodestate = State (pfrom->GetId ());
1275+ if (nodestate->nUnconnectingHeaders > 0 ) {
1276+ LogPrint (BCLog::NET, " peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n " , pfrom->GetId (), nodestate->nUnconnectingHeaders );
1277+ }
1278+ nodestate->nUnconnectingHeaders = 0 ;
1279+
1280+ assert (pindexLast);
1281+ UpdateBlockAvailability (pfrom->GetId (), pindexLast->GetBlockHash ());
1282+
1283+ // From here, pindexBestKnownBlock should be guaranteed to be non-null,
1284+ // because it is set in UpdateBlockAvailability. Some nullptr checks
1285+ // are still present, however, as belt-and-suspenders.
1286+
1287+ if (nCount == MAX_HEADERS_RESULTS) {
1288+ // Headers message had its maximum size; the peer may have more headers.
1289+ // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
1290+ // from there instead.
1291+ LogPrint (BCLog::NET, " more getheaders (%d) to end to peer=%d (startheight:%d)\n " , pindexLast->nHeight , pfrom->GetId (), pfrom->nStartingHeight );
1292+ connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETHEADERS, chainActive.GetLocator (pindexLast), uint256 ()));
1293+ }
1294+
1295+ bool fCanDirectFetch = CanDirectFetch (chainparams.GetConsensus ());
1296+ // If this set of headers is valid and ends in a block with at least as
1297+ // much work as our tip, download as much as possible.
1298+ if (fCanDirectFetch && pindexLast->IsValid (BLOCK_VALID_TREE) && chainActive.Tip ()->nChainWork <= pindexLast->nChainWork ) {
1299+ std::vector<const CBlockIndex*> vToFetch;
1300+ const CBlockIndex *pindexWalk = pindexLast;
1301+ // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
1302+ while (pindexWalk && !chainActive.Contains (pindexWalk) && vToFetch.size () <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
1303+ if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
1304+ !mapBlocksInFlight.count (pindexWalk->GetBlockHash ()) &&
1305+ (!IsWitnessEnabled (pindexWalk->pprev , chainparams.GetConsensus ()) || State (pfrom->GetId ())->fHaveWitness )) {
1306+ // We don't have this block, and it's not yet in flight.
1307+ vToFetch.push_back (pindexWalk);
1308+ }
1309+ pindexWalk = pindexWalk->pprev ;
1310+ }
1311+ // If pindexWalk still isn't on our main chain, we're looking at a
1312+ // very large reorg at a time we think we're close to caught up to
1313+ // the main chain -- this shouldn't really happen. Bail out on the
1314+ // direct fetch and rely on parallel download instead.
1315+ if (!chainActive.Contains (pindexWalk)) {
1316+ LogPrint (BCLog::NET, " Large reorg, won't direct fetch to %s (%d)\n " ,
1317+ pindexLast->GetBlockHash ().ToString (),
1318+ pindexLast->nHeight );
1319+ } else {
1320+ std::vector<CInv> vGetData;
1321+ // Download as much as possible, from earliest to latest.
1322+ for (const CBlockIndex *pindex : reverse_iterate (vToFetch)) {
1323+ if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
1324+ // Can't download any more from this peer
1325+ break ;
1326+ }
1327+ uint32_t nFetchFlags = GetFetchFlags (pfrom);
1328+ vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
1329+ MarkBlockAsInFlight (pfrom->GetId (), pindex->GetBlockHash (), pindex);
1330+ LogPrint (BCLog::NET, " Requesting block %s from peer=%d\n " ,
1331+ pindex->GetBlockHash ().ToString (), pfrom->GetId ());
1332+ }
1333+ if (vGetData.size () > 1 ) {
1334+ LogPrint (BCLog::NET, " Downloading blocks toward %s (%d) via headers direct fetch\n " ,
1335+ pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
1336+ }
1337+ if (vGetData.size () > 0 ) {
1338+ if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size () == 1 && mapBlocksInFlight.size () == 1 && pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN)) {
1339+ // In any case, we want to download using a compact block, not a regular one
1340+ vGetData[0 ] = CInv (MSG_CMPCT_BLOCK, vGetData[0 ].hash );
1341+ }
1342+ connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETDATA, vGetData));
1343+ }
1344+ }
1345+ }
1346+ // If we're in IBD, we want outbound peers that will serve us a useful
1347+ // chain. Disconnect peers that are on chains with insufficient work.
1348+ if (IsInitialBlockDownload () && nCount != MAX_HEADERS_RESULTS) {
1349+ // When nCount < MAX_HEADERS_RESULTS, we know we have no more
1350+ // headers to fetch from this peer.
1351+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock ->nChainWork < nMinimumChainWork) {
1352+ // This peer has too little work on their headers chain to help
1353+ // us sync -- disconnect if using an outbound slot (unless
1354+ // whitelisted or addnode).
1355+ // Note: We compare their tip to nMinimumChainWork (rather than
1356+ // chainActive.Tip()) because we won't start block download
1357+ // until we have a headers chain that has at least
1358+ // nMinimumChainWork, even if a peer has a chain past our tip,
1359+ // as an anti-DoS measure.
1360+ if (IsOutboundDisconnectionCandidate (pfrom)) {
1361+ LogPrintf (" Disconnecting outbound peer %d -- headers chain has insufficient work\n " , pfrom->GetId ());
1362+ pfrom->fDisconnect = true ;
1363+ }
1364+ }
1365+ }
1366+
1367+ if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate (pfrom) && nodestate->pindexBestKnownBlock != nullptr ) {
1368+ // If this is an outbound peer, check to see if we should protect
1369+ // it from the bad/lagging chain logic.
1370+ if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock ->nChainWork >= chainActive.Tip ()->nChainWork && !nodestate->m_chain_sync .m_protect ) {
1371+ nodestate->m_chain_sync .m_protect = true ;
1372+ ++g_outbound_peers_with_protect_from_disconnect;
1373+ }
1374+ }
1375+ }
1376+
1377+ return true ;
1378+ }
1379+
12081380bool static ProcessMessage (CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool >& interruptMsgProc)
12091381{
12101382 LogPrint (BCLog::NET, " received: %s (%u bytes) peer=%d\n " , SanitizeString (strCommand), vRecv.size (), pfrom->GetId ());
@@ -2308,169 +2480,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
23082480 ReadCompactSize (vRecv); // ignore tx count; assume it is 0.
23092481 }
23102482
2311- if (nCount == 0 ) {
2312- // Nothing interesting. Stop asking this peers for more headers.
2313- return true ;
2314- }
2315-
2316- const CBlockIndex *pindexLast = nullptr ;
2317- {
2318- LOCK (cs_main);
2319- CNodeState *nodestate = State (pfrom->GetId ());
2320-
2321- // If this looks like it could be a block announcement (nCount <
2322- // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
2323- // don't connect:
2324- // - Send a getheaders message in response to try to connect the chain.
2325- // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
2326- // don't connect before giving DoS points
2327- // - Once a headers message is received that is valid and does connect,
2328- // nUnconnectingHeaders gets reset back to 0.
2329- if (mapBlockIndex.find (headers[0 ].hashPrevBlock ) == mapBlockIndex.end () && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
2330- nodestate->nUnconnectingHeaders ++;
2331- connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETHEADERS, chainActive.GetLocator (pindexBestHeader), uint256 ()));
2332- LogPrint (BCLog::NET, " received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n " ,
2333- headers[0 ].GetHash ().ToString (),
2334- headers[0 ].hashPrevBlock .ToString (),
2335- pindexBestHeader->nHeight ,
2336- pfrom->GetId (), nodestate->nUnconnectingHeaders );
2337- // Set hashLastUnknownBlock for this peer, so that if we
2338- // eventually get the headers - even from a different peer -
2339- // we can use this peer to download.
2340- UpdateBlockAvailability (pfrom->GetId (), headers.back ().GetHash ());
2341-
2342- if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0 ) {
2343- Misbehaving (pfrom->GetId (), 20 );
2344- }
2345- return true ;
2346- }
2347-
2348- uint256 hashLastBlock;
2349- for (const CBlockHeader& header : headers) {
2350- if (!hashLastBlock.IsNull () && header.hashPrevBlock != hashLastBlock) {
2351- Misbehaving (pfrom->GetId (), 20 );
2352- return error (" non-continuous headers sequence" );
2353- }
2354- hashLastBlock = header.GetHash ();
2355- }
2356- }
2357-
2358- CValidationState state;
2359- if (!ProcessNewBlockHeaders (headers, state, chainparams, &pindexLast)) {
2360- int nDoS;
2361- if (state.IsInvalid (nDoS)) {
2362- if (nDoS > 0 ) {
2363- LOCK (cs_main);
2364- Misbehaving (pfrom->GetId (), nDoS);
2365- }
2366- return error (" invalid header received" );
2367- }
2368- }
2369-
2370- {
2371- LOCK (cs_main);
2372- CNodeState *nodestate = State (pfrom->GetId ());
2373- if (nodestate->nUnconnectingHeaders > 0 ) {
2374- LogPrint (BCLog::NET, " peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n " , pfrom->GetId (), nodestate->nUnconnectingHeaders );
2375- }
2376- nodestate->nUnconnectingHeaders = 0 ;
2377-
2378- assert (pindexLast);
2379- UpdateBlockAvailability (pfrom->GetId (), pindexLast->GetBlockHash ());
2380-
2381- // From here, pindexBestKnownBlock should be guaranteed to be non-null,
2382- // because it is set in UpdateBlockAvailability. Some nullptr checks
2383- // are still present, however, as belt-and-suspenders.
2384-
2385- if (nCount == MAX_HEADERS_RESULTS) {
2386- // Headers message had its maximum size; the peer may have more headers.
2387- // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
2388- // from there instead.
2389- LogPrint (BCLog::NET, " more getheaders (%d) to end to peer=%d (startheight:%d)\n " , pindexLast->nHeight , pfrom->GetId (), pfrom->nStartingHeight );
2390- connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETHEADERS, chainActive.GetLocator (pindexLast), uint256 ()));
2391- }
2392-
2393- bool fCanDirectFetch = CanDirectFetch (chainparams.GetConsensus ());
2394- // If this set of headers is valid and ends in a block with at least as
2395- // much work as our tip, download as much as possible.
2396- if (fCanDirectFetch && pindexLast->IsValid (BLOCK_VALID_TREE) && chainActive.Tip ()->nChainWork <= pindexLast->nChainWork ) {
2397- std::vector<const CBlockIndex*> vToFetch;
2398- const CBlockIndex *pindexWalk = pindexLast;
2399- // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2400- while (pindexWalk && !chainActive.Contains (pindexWalk) && vToFetch.size () <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2401- if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2402- !mapBlocksInFlight.count (pindexWalk->GetBlockHash ()) &&
2403- (!IsWitnessEnabled (pindexWalk->pprev , chainparams.GetConsensus ()) || State (pfrom->GetId ())->fHaveWitness )) {
2404- // We don't have this block, and it's not yet in flight.
2405- vToFetch.push_back (pindexWalk);
2406- }
2407- pindexWalk = pindexWalk->pprev ;
2408- }
2409- // If pindexWalk still isn't on our main chain, we're looking at a
2410- // very large reorg at a time we think we're close to caught up to
2411- // the main chain -- this shouldn't really happen. Bail out on the
2412- // direct fetch and rely on parallel download instead.
2413- if (!chainActive.Contains (pindexWalk)) {
2414- LogPrint (BCLog::NET, " Large reorg, won't direct fetch to %s (%d)\n " ,
2415- pindexLast->GetBlockHash ().ToString (),
2416- pindexLast->nHeight );
2417- } else {
2418- std::vector<CInv> vGetData;
2419- // Download as much as possible, from earliest to latest.
2420- for (const CBlockIndex *pindex : reverse_iterate (vToFetch)) {
2421- if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2422- // Can't download any more from this peer
2423- break ;
2424- }
2425- uint32_t nFetchFlags = GetFetchFlags (pfrom);
2426- vGetData.push_back (CInv (MSG_BLOCK | nFetchFlags, pindex->GetBlockHash ()));
2427- MarkBlockAsInFlight (pfrom->GetId (), pindex->GetBlockHash (), pindex);
2428- LogPrint (BCLog::NET, " Requesting block %s from peer=%d\n " ,
2429- pindex->GetBlockHash ().ToString (), pfrom->GetId ());
2430- }
2431- if (vGetData.size () > 1 ) {
2432- LogPrint (BCLog::NET, " Downloading blocks toward %s (%d) via headers direct fetch\n " ,
2433- pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
2434- }
2435- if (vGetData.size () > 0 ) {
2436- if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size () == 1 && mapBlocksInFlight.size () == 1 && pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN)) {
2437- // In any case, we want to download using a compact block, not a regular one
2438- vGetData[0 ] = CInv (MSG_CMPCT_BLOCK, vGetData[0 ].hash );
2439- }
2440- connman->PushMessage (pfrom, msgMaker.Make (NetMsgType::GETDATA, vGetData));
2441- }
2442- }
2443- }
2444- // If we're in IBD, we want outbound peers that will serve us a useful
2445- // chain. Disconnect peers that are on chains with insufficient work.
2446- if (IsInitialBlockDownload () && nCount != MAX_HEADERS_RESULTS) {
2447- // When nCount < MAX_HEADERS_RESULTS, we know we have no more
2448- // headers to fetch from this peer.
2449- if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock ->nChainWork < nMinimumChainWork) {
2450- // This peer has too little work on their headers chain to help
2451- // us sync -- disconnect if using an outbound slot (unless
2452- // whitelisted or addnode).
2453- // Note: We compare their tip to nMinimumChainWork (rather than
2454- // chainActive.Tip()) because we won't start block download
2455- // until we have a headers chain that has at least
2456- // nMinimumChainWork, even if a peer has a chain past our tip,
2457- // as an anti-DoS measure.
2458- if (IsOutboundDisconnectionCandidate (pfrom)) {
2459- LogPrintf (" Disconnecting outbound peer %d -- headers chain has insufficient work\n " , pfrom->GetId ());
2460- pfrom->fDisconnect = true ;
2461- }
2462- }
2463- }
2464-
2465- if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate (pfrom) && nodestate->pindexBestKnownBlock != nullptr ) {
2466- // If this is an outbound peer, check to see if we should protect
2467- // it from the bad/lagging chain logic.
2468- if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock ->nChainWork >= chainActive.Tip ()->nChainWork && !nodestate->m_chain_sync .m_protect ) {
2469- nodestate->m_chain_sync .m_protect = true ;
2470- ++g_outbound_peers_with_protect_from_disconnect;
2471- }
2472- }
2473- }
2483+ return ProcessHeadersMessage (pfrom, connman, headers, chainparams);
24742484 }
24752485
24762486 else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex ) // Ignore blocks received while importing
0 commit comments