@@ -1205,6 +1205,178 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
1205
1205
connman->PushMessage (pfrom, msgMaker.Make (nSendFlags, NetMsgType::BLOCKTXN, resp));
1206
1206
}
1207
1207
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
+
1208
1380
bool static ProcessMessage (CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool >& interruptMsgProc)
1209
1381
{
1210
1382
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
2308
2480
ReadCompactSize (vRecv); // ignore tx count; assume it is 0.
2309
2481
}
2310
2482
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);
2474
2484
}
2475
2485
2476
2486
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex ) // Ignore blocks received while importing
0 commit comments