@@ -207,6 +207,10 @@ struct CNodeState {
207
207
std::string name;
208
208
// List of asynchronously-determined block rejections to notify this peer about.
209
209
std::vector<CBlockReject> rejects;
210
+ // The best known block we know this peer has announced.
211
+ CBlockIndex *pindexBestKnownBlock;
212
+ // The hash of the last unknown block this peer has announced.
213
+ uint256 hashLastUnknownBlock;
210
214
list<QueuedBlock> vBlocksInFlight;
211
215
int nBlocksInFlight;
212
216
list<uint256> vBlocksToDownload;
@@ -217,6 +221,8 @@ struct CNodeState {
217
221
CNodeState () {
218
222
nMisbehavior = 0 ;
219
223
fShouldBan = false ;
224
+ pindexBestKnownBlock = NULL ;
225
+ hashLastUnknownBlock = uint256 (0 );
220
226
nBlocksToDownload = 0 ;
221
227
nBlocksInFlight = 0 ;
222
228
nLastBlockReceive = 0 ;
@@ -313,6 +319,39 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256 &hash) {
313
319
mapBlocksInFlight[hash] = std::make_pair (nodeid, it);
314
320
}
315
321
322
+ /* * Check whether the last unknown block a peer advertized is not yet known. */
323
+ void ProcessBlockAvailability (NodeId nodeid) {
324
+ CNodeState *state = State (nodeid);
325
+ assert (state != NULL );
326
+
327
+ if (state->hashLastUnknownBlock != 0 ) {
328
+ map<uint256, CBlockIndex*>::iterator itOld = mapBlockIndex.find (state->hashLastUnknownBlock );
329
+ if (itOld != mapBlockIndex.end () && itOld->second ->nChainWork > 0 ) {
330
+ if (state->pindexBestKnownBlock == NULL || itOld->second ->nChainWork >= state->pindexBestKnownBlock ->nChainWork )
331
+ state->pindexBestKnownBlock = itOld->second ;
332
+ state->hashLastUnknownBlock = uint256 (0 );
333
+ }
334
+ }
335
+ }
336
+
337
+ /* * Update tracking information about which blocks a peer is assumed to have. */
338
+ void UpdateBlockAvailability (NodeId nodeid, const uint256 &hash) {
339
+ CNodeState *state = State (nodeid);
340
+ assert (state != NULL );
341
+
342
+ ProcessBlockAvailability (nodeid);
343
+
344
+ map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find (hash);
345
+ if (it != mapBlockIndex.end () && it->second ->nChainWork > 0 ) {
346
+ // An actually better block was announced.
347
+ if (state->pindexBestKnownBlock == NULL || it->second ->nChainWork >= state->pindexBestKnownBlock ->nChainWork )
348
+ state->pindexBestKnownBlock = it->second ;
349
+ } else {
350
+ // An unknown block was announced; just assume that the latest one is the best one.
351
+ state->hashLastUnknownBlock = hash;
352
+ }
353
+ }
354
+
316
355
} // anon namespace
317
356
318
357
bool GetNodeStateStats (NodeId nodeid, CNodeStateStats &stats) {
@@ -321,6 +360,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
321
360
if (state == NULL )
322
361
return false ;
323
362
stats.nMisbehavior = state->nMisbehavior ;
363
+ stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock ->nHeight : -1 ;
324
364
return true ;
325
365
}
326
366
@@ -374,8 +414,11 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
374
414
break ;
375
415
// Exponentially larger steps back, plus the genesis block.
376
416
int nHeight = std::max (pindex->nHeight - nStep, 0 );
417
+ // Jump back quickly to the same height as the chain.
418
+ if (pindex->nHeight > nHeight)
419
+ pindex = pindex->GetAncestor (nHeight);
377
420
// In case pindex is not in this chain, iterate pindex->pprev to find blocks.
378
- while (pindex-> nHeight > nHeight && !Contains (pindex))
421
+ while (!Contains (pindex))
379
422
pindex = pindex->pprev ;
380
423
// If pindex is in this chain, use direct height-based access.
381
424
if (pindex->nHeight > nHeight)
@@ -402,6 +445,8 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
402
445
}
403
446
404
447
CBlockIndex *CChain::FindFork (CBlockIndex *pindex) const {
448
+ if (pindex->nHeight > Height ())
449
+ pindex = pindex->GetAncestor (Height ());
405
450
while (pindex && !Contains (pindex))
406
451
pindex = pindex->pprev ;
407
452
return pindex;
@@ -2111,6 +2156,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block)
2111
2156
{
2112
2157
pindexNew->pprev = (*miPrev).second ;
2113
2158
pindexNew->nHeight = pindexNew->pprev ->nHeight + 1 ;
2159
+ pindexNew->BuildSkip ();
2114
2160
}
2115
2161
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev ->nChainWork : 0 ) + pindexNew->GetBlockWork ();
2116
2162
pindexNew->RaiseValidity (BLOCK_VALID_TREE);
@@ -2468,6 +2514,55 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
2468
2514
return (nFound >= nRequired);
2469
2515
}
2470
2516
2517
+ /* * Turn the lowest '1' bit in the binary representation of a number into a '0'. */
2518
+ int static inline InvertLowestOne (int n) { return n & (n - 1 ); }
2519
+
2520
+ /* * Compute what height to jump back to with the CBlockIndex::pskip pointer. */
2521
+ int static inline GetSkipHeight (int height) {
2522
+ if (height < 2 )
2523
+ return 0 ;
2524
+
2525
+ // Determine which height to jump back to. Any number strictly lower than height is acceptable,
2526
+ // but the following expression seems to perform well in simulations (max 110 steps to go back
2527
+ // up to 2**18 blocks).
2528
+ return (height & 1 ) ? InvertLowestOne (InvertLowestOne (height - 1 )) + 1 : InvertLowestOne (height);
2529
+ }
2530
+
2531
+ CBlockIndex* CBlockIndex::GetAncestor (int height)
2532
+ {
2533
+ if (height > nHeight || height < 0 )
2534
+ return NULL ;
2535
+
2536
+ CBlockIndex* pindexWalk = this ;
2537
+ int heightWalk = nHeight;
2538
+ while (heightWalk > height) {
2539
+ int heightSkip = GetSkipHeight (heightWalk);
2540
+ int heightSkipPrev = GetSkipHeight (heightWalk - 1 );
2541
+ if (heightSkip == height ||
2542
+ (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
2543
+ heightSkipPrev >= height))) {
2544
+ // Only follow pskip if pprev->pskip isn't better than pskip->pprev.
2545
+ pindexWalk = pindexWalk->pskip ;
2546
+ heightWalk = heightSkip;
2547
+ } else {
2548
+ pindexWalk = pindexWalk->pprev ;
2549
+ heightWalk--;
2550
+ }
2551
+ }
2552
+ return pindexWalk;
2553
+ }
2554
+
2555
+ const CBlockIndex* CBlockIndex::GetAncestor (int height) const
2556
+ {
2557
+ return const_cast <CBlockIndex*>(this )->GetAncestor (height);
2558
+ }
2559
+
2560
+ void CBlockIndex::BuildSkip ()
2561
+ {
2562
+ if (pprev)
2563
+ pskip = pprev->GetAncestor (GetSkipHeight (nHeight));
2564
+ }
2565
+
2471
2566
void PushGetBlocks (CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
2472
2567
{
2473
2568
AssertLockHeld (cs_main);
@@ -2818,6 +2913,8 @@ bool static LoadBlockIndexDB()
2818
2913
setBlockIndexValid.insert (pindex);
2819
2914
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork ))
2820
2915
pindexBestInvalid = pindex;
2916
+ if (pindex->pprev )
2917
+ pindex->BuildSkip ();
2821
2918
}
2822
2919
2823
2920
// Load block file info
@@ -3613,6 +3710,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
3613
3710
PushGetBlocks (pfrom, chainActive.Tip (), GetOrphanRoot (inv.hash ));
3614
3711
}
3615
3712
3713
+ if (inv.type == MSG_BLOCK)
3714
+ UpdateBlockAvailability (pfrom->GetId (), inv.hash );
3715
+
3616
3716
// Track requests for our stuff
3617
3717
g_signals.Inventory (inv.hash );
3618
3718
}
@@ -4359,6 +4459,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
4359
4459
pto->fDisconnect = true ;
4360
4460
}
4361
4461
4462
+ // Update knowledge of peer's block availability.
4463
+ ProcessBlockAvailability (pto->GetId ());
4464
+
4362
4465
//
4363
4466
// Message: getdata (blocks)
4364
4467
//
0 commit comments