@@ -63,7 +63,7 @@ CCriticalSection cs_main;
63
63
BlockMap mapBlockIndex;
64
64
CChain chainActive;
65
65
CBlockIndex *pindexBestHeader = NULL ;
66
- int64_t nTimeBestReceived = 0 ;
66
+ int64_t nTimeBestReceived = 0 ; // Used only to inform the wallet of when we last received a block
67
67
CWaitableCriticalSection csBestBlock;
68
68
CConditionVariable cvBlockChange;
69
69
int nScriptCheckThreads = 0 ;
@@ -691,6 +691,16 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
691
691
CCoinsViewCache *pcoinsTip = NULL ;
692
692
CBlockTreeDB *pblocktree = NULL ;
693
693
694
+ enum FlushStateMode {
695
+ FLUSH_STATE_NONE,
696
+ FLUSH_STATE_IF_NEEDED,
697
+ FLUSH_STATE_PERIODIC,
698
+ FLUSH_STATE_ALWAYS
699
+ };
700
+
701
+ // See definition for documentation
702
+ bool static FlushStateToDisk (CValidationState &state, FlushStateMode mode);
703
+
694
704
// ////////////////////////////////////////////////////////////////////////////
695
705
//
696
706
// mapOrphanTransactions
@@ -1581,6 +1591,9 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const
1581
1591
BOOST_FOREACH (const uint256& hashTx, vHashTxToUncache)
1582
1592
pcoinsTip->Uncache (hashTx);
1583
1593
}
1594
+ // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
1595
+ CValidationState stateDummy;
1596
+ FlushStateToDisk (stateDummy, FLUSH_STATE_PERIODIC);
1584
1597
return res;
1585
1598
}
1586
1599
@@ -2565,13 +2578,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
2565
2578
return true ;
2566
2579
}
2567
2580
2568
- enum FlushStateMode {
2569
- FLUSH_STATE_NONE,
2570
- FLUSH_STATE_IF_NEEDED,
2571
- FLUSH_STATE_PERIODIC,
2572
- FLUSH_STATE_ALWAYS
2573
- };
2574
-
2575
2581
/* *
2576
2582
* Update the on-disk chain state.
2577
2583
* The caches and indexes are flushed depending on the mode we're called with
@@ -2691,7 +2697,6 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
2691
2697
chainActive.SetTip (pindexNew);
2692
2698
2693
2699
// New best block
2694
- nTimeBestReceived = GetTime ();
2695
2700
mempool.AddTransactionsUpdated (1 );
2696
2701
2697
2702
cvBlockChange.notify_all ();
@@ -3676,6 +3681,8 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
3676
3681
if (ppindex)
3677
3682
*ppindex = pindex;
3678
3683
3684
+ CheckBlockIndex (chainparams.GetConsensus ());
3685
+
3679
3686
return true ;
3680
3687
}
3681
3688
@@ -3703,6 +3710,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
3703
3710
// not process unrequested blocks.
3704
3711
bool fTooFarAhead = (pindex->nHeight > int (chainActive.Height () + MIN_BLOCKS_TO_KEEP));
3705
3712
3713
+ // TODO: Decouple this function from the block download logic by removing fRequested
3714
+ // This requires some new chain datastructure to efficiently look up if a
3715
+ // block is in a chain leading to a candidate for best tip, despite not
3716
+ // being such a candidate itself.
3717
+
3706
3718
// TODO: deal better with return value and error conditions for duplicate
3707
3719
// and unrequested blocks.
3708
3720
if (fAlreadyHave ) return true ;
@@ -3751,13 +3763,11 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
3751
3763
{
3752
3764
{
3753
3765
LOCK (cs_main);
3754
- bool fRequested = MarkBlockAsReceived (pblock->GetHash ());
3755
- fRequested |= fForceProcessing ;
3756
3766
3757
3767
// Store to disk
3758
3768
CBlockIndex *pindex = NULL ;
3759
3769
bool fNewBlock = false ;
3760
- bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fRequested , dbp, &fNewBlock );
3770
+ bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fForceProcessing , dbp, &fNewBlock );
3761
3771
if (pindex && pfrom) {
3762
3772
mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
3763
3773
if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
@@ -4269,6 +4279,9 @@ bool RewindBlockIndex(const CChainParams& params)
4269
4279
return true ;
4270
4280
}
4271
4281
4282
+ // May NOT be used after any connections are up as much
4283
+ // of the peer-processing logic assumes a consistent
4284
+ // block index state
4272
4285
void UnloadBlockIndex ()
4273
4286
{
4274
4287
LOCK (cs_main);
@@ -4279,18 +4292,12 @@ void UnloadBlockIndex()
4279
4292
mempool.clear ();
4280
4293
mapOrphanTransactions.clear ();
4281
4294
mapOrphanTransactionsByPrev.clear ();
4282
- nSyncStarted = 0 ;
4283
4295
mapBlocksUnlinked.clear ();
4284
4296
vinfoBlockFile.clear ();
4285
4297
nLastBlockFile = 0 ;
4286
4298
nBlockSequenceId = 1 ;
4287
- mapBlockSource.clear ();
4288
- mapBlocksInFlight.clear ();
4289
- nPreferredDownload = 0 ;
4290
4299
setDirtyBlockIndex.clear ();
4291
4300
setDirtyFileInfo.clear ();
4292
- mapNodeState.clear ();
4293
- recentRejects.reset (NULL );
4294
4301
versionbitscache.Clear ();
4295
4302
for (int b = 0 ; b < VERSIONBITS_NUM_BITS; b++) {
4296
4303
warningcache[b].clear ();
@@ -4315,9 +4322,6 @@ bool InitBlockIndex(const CChainParams& chainparams)
4315
4322
{
4316
4323
LOCK (cs_main);
4317
4324
4318
- // Initialize global variables that cannot be constructed at startup.
4319
- recentRejects.reset (new CRollingBloomFilter (120000 , 0.000001 ));
4320
-
4321
4325
// Check whether we're already initialized
4322
4326
if (chainActive.Genesis () != NULL )
4323
4327
return true ;
@@ -4706,6 +4710,11 @@ std::string GetWarnings(const std::string& strFor)
4706
4710
// blockchain -> download logic notification
4707
4711
//
4708
4712
4713
+ PeerLogicValidation::PeerLogicValidation (CConnman* connmanIn) : connman(connmanIn) {
4714
+ // Initialize global variables that cannot be constructed at startup.
4715
+ recentRejects.reset (new CRollingBloomFilter (120000 , 0.000001 ));
4716
+ }
4717
+
4709
4718
void PeerLogicValidation::UpdatedBlockTip (const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload ) {
4710
4719
const int nNewHeight = pindexNew->nHeight ;
4711
4720
connman->SetBestHeight (nNewHeight);
@@ -4732,6 +4741,8 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
4732
4741
}
4733
4742
});
4734
4743
}
4744
+
4745
+ nTimeBestReceived = GetTime ();
4735
4746
}
4736
4747
4737
4748
void PeerLogicValidation::BlockChecked (const CBlock& block, const CValidationState& state) {
@@ -5690,7 +5701,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5690
5701
Misbehaving (pfrom->GetId (), nDoS);
5691
5702
}
5692
5703
}
5693
- FlushStateToDisk (state, FLUSH_STATE_PERIODIC);
5694
5704
}
5695
5705
5696
5706
@@ -5826,8 +5836,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5826
5836
return ProcessMessage (pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
5827
5837
}
5828
5838
}
5829
-
5830
- CheckBlockIndex (chainparams.GetConsensus ());
5831
5839
}
5832
5840
5833
5841
else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex ) // Ignore blocks received while importing
@@ -5859,12 +5867,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5859
5867
std::vector<CInv> invs;
5860
5868
invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
5861
5869
pfrom->PushMessage (NetMsgType::GETDATA, invs);
5862
- } else
5870
+ } else {
5871
+ MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
5863
5872
fBlockRead = true ;
5873
+ }
5864
5874
} // Don't hold cs_main when we call into ProcessNewBlock
5865
5875
if (fBlockRead ) {
5866
5876
CValidationState state;
5867
- ProcessNewBlock (state, chainparams, pfrom, &block, false , NULL );
5877
+ // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
5878
+ // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
5879
+ ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL );
5868
5880
int nDoS;
5869
5881
if (state.IsInvalid (nDoS)) {
5870
5882
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -6020,8 +6032,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
6020
6032
}
6021
6033
}
6022
6034
}
6023
-
6024
- CheckBlockIndex (chainparams.GetConsensus ());
6025
6035
}
6026
6036
6027
6037
NotifyHeaderTip ();
@@ -6040,6 +6050,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
6040
6050
// Such an unrequested block may still be processed, subject to the
6041
6051
// conditions in AcceptBlock().
6042
6052
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload ();
6053
+ {
6054
+ LOCK (cs_main);
6055
+ // Also always process if we requested the block explicitly, as we may
6056
+ // need it even though it is not a candidate for a new best tip.
6057
+ forceProcessing |= MarkBlockAsReceived (block.GetHash ());
6058
+ }
6043
6059
ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
6044
6060
int nDoS;
6045
6061
if (state.IsInvalid (nDoS)) {
0 commit comments