@@ -63,7 +63,7 @@ CCriticalSection cs_main;
6363BlockMap mapBlockIndex;
6464CChain chainActive;
6565CBlockIndex *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
6767CWaitableCriticalSection csBestBlock;
6868CConditionVariable cvBlockChange;
6969int nScriptCheckThreads = 0 ;
@@ -691,6 +691,16 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
691691CCoinsViewCache *pcoinsTip = NULL ;
692692CBlockTreeDB *pblocktree = NULL ;
693693
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+
694704// ////////////////////////////////////////////////////////////////////////////
695705//
696706// mapOrphanTransactions
@@ -1581,6 +1591,9 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const
15811591 BOOST_FOREACH (const uint256& hashTx, vHashTxToUncache)
15821592 pcoinsTip->Uncache (hashTx);
15831593 }
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 );
15841597 return res;
15851598}
15861599
@@ -2565,13 +2578,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
25652578 return true ;
25662579}
25672580
2568- enum FlushStateMode {
2569- FLUSH_STATE_NONE ,
2570- FLUSH_STATE_IF_NEEDED ,
2571- FLUSH_STATE_PERIODIC ,
2572- FLUSH_STATE_ALWAYS
2573- };
2574-
25752581/* *
25762582 * Update the on-disk chain state.
25772583 * 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) {
26912697 chainActive.SetTip (pindexNew);
26922698
26932699 // New best block
2694- nTimeBestReceived = GetTime ();
26952700 mempool.AddTransactionsUpdated (1 );
26962701
26972702 cvBlockChange.notify_all ();
@@ -3676,6 +3681,8 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
36763681 if (ppindex)
36773682 *ppindex = pindex;
36783683
3684+ CheckBlockIndex (chainparams.GetConsensus ());
3685+
36793686 return true ;
36803687}
36813688
@@ -3703,6 +3710,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
37033710 // not process unrequested blocks.
37043711 bool fTooFarAhead = (pindex->nHeight > int (chainActive.Height () + MIN_BLOCKS_TO_KEEP ));
37053712
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+
37063718 // TODO: deal better with return value and error conditions for duplicate
37073719 // and unrequested blocks.
37083720 if (fAlreadyHave ) return true ;
@@ -3751,13 +3763,11 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
37513763{
37523764 {
37533765 LOCK (cs_main);
3754- bool fRequested = MarkBlockAsReceived (pblock->GetHash ());
3755- fRequested |= fForceProcessing ;
37563766
37573767 // Store to disk
37583768 CBlockIndex *pindex = NULL ;
37593769 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 );
37613771 if (pindex && pfrom) {
37623772 mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
37633773 if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
@@ -4269,6 +4279,9 @@ bool RewindBlockIndex(const CChainParams& params)
42694279 return true ;
42704280}
42714281
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
42724285void UnloadBlockIndex ()
42734286{
42744287 LOCK (cs_main);
@@ -4279,18 +4292,12 @@ void UnloadBlockIndex()
42794292 mempool.clear ();
42804293 mapOrphanTransactions.clear ();
42814294 mapOrphanTransactionsByPrev.clear ();
4282- nSyncStarted = 0 ;
42834295 mapBlocksUnlinked.clear ();
42844296 vinfoBlockFile.clear ();
42854297 nLastBlockFile = 0 ;
42864298 nBlockSequenceId = 1 ;
4287- mapBlockSource.clear ();
4288- mapBlocksInFlight.clear ();
4289- nPreferredDownload = 0 ;
42904299 setDirtyBlockIndex.clear ();
42914300 setDirtyFileInfo.clear ();
4292- mapNodeState.clear ();
4293- recentRejects.reset (NULL );
42944301 versionbitscache.Clear ();
42954302 for (int b = 0 ; b < VERSIONBITS_NUM_BITS ; b++) {
42964303 warningcache[b].clear ();
@@ -4315,9 +4322,6 @@ bool InitBlockIndex(const CChainParams& chainparams)
43154322{
43164323 LOCK (cs_main);
43174324
4318- // Initialize global variables that cannot be constructed at startup.
4319- recentRejects.reset (new CRollingBloomFilter (120000 , 0.000001 ));
4320-
43214325 // Check whether we're already initialized
43224326 if (chainActive.Genesis () != NULL )
43234327 return true ;
@@ -4706,6 +4710,11 @@ std::string GetWarnings(const std::string& strFor)
47064710// blockchain -> download logic notification
47074711//
47084712
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+
47094718void PeerLogicValidation::UpdatedBlockTip (const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload ) {
47104719 const int nNewHeight = pindexNew->nHeight ;
47114720 connman->SetBestHeight (nNewHeight);
@@ -4732,6 +4741,8 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
47324741 }
47334742 });
47344743 }
4744+
4745+ nTimeBestReceived = GetTime ();
47354746}
47364747
47374748void PeerLogicValidation::BlockChecked (const CBlock& block, const CValidationState& state) {
@@ -5690,7 +5701,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
56905701 Misbehaving (pfrom->GetId (), nDoS);
56915702 }
56925703 }
5693- FlushStateToDisk (state, FLUSH_STATE_PERIODIC );
56945704 }
56955705
56965706
@@ -5826,8 +5836,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
58265836 return ProcessMessage (pfrom, NetMsgType::HEADERS , vHeadersMsg, nTimeReceived, chainparams, connman);
58275837 }
58285838 }
5829-
5830- CheckBlockIndex (chainparams.GetConsensus ());
58315839 }
58325840
58335841 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,
58595867 std::vector<CInv> invs;
58605868 invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
58615869 pfrom->PushMessage (NetMsgType::GETDATA , invs);
5862- } else
5870+ } else {
5871+ MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
58635872 fBlockRead = true ;
5873+ }
58645874 } // Don't hold cs_main when we call into ProcessNewBlock
58655875 if (fBlockRead ) {
58665876 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 );
58685880 int nDoS;
58695881 if (state.IsInvalid (nDoS)) {
58705882 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,
60206032 }
60216033 }
60226034 }
6023-
6024- CheckBlockIndex (chainparams.GetConsensus ());
60256035 }
60266036
60276037 NotifyHeaderTip ();
@@ -6040,6 +6050,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
60406050 // Such an unrequested block may still be processed, subject to the
60416051 // conditions in AcceptBlock().
60426052 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+ }
60436059 ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
60446060 int nDoS;
60456061 if (state.IsInvalid (nDoS)) {
0 commit comments