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