@@ -658,6 +658,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
658658 CBlockIndex* pindex = (*mi).second ;
659659 if (chain.Contains (pindex))
660660 return pindex;
661+ if (pindex->GetAncestor (chain.Height ()) == chain.Tip ()) {
662+ return chain.Tip ();
663+ }
661664 }
662665 }
663666 return chain.Genesis ();
@@ -2777,7 +2780,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
27772780}
27782781
27792782/* * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
2780- bool static DisconnectTip (CValidationState& state, const CChainParams& chainparams)
2783+ bool static DisconnectTip (CValidationState& state, const CChainParams& chainparams, bool fBare = false )
27812784{
27822785 CBlockIndex *pindexDelete = chainActive.Tip ();
27832786 assert (pindexDelete);
@@ -2797,24 +2800,28 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
27972800 // Write the chain state to disk, if necessary.
27982801 if (!FlushStateToDisk (state, FLUSH_STATE_IF_NEEDED))
27992802 return false ;
2800- // Resurrect mempool transactions from the disconnected block.
2801- std::vector<uint256> vHashUpdate;
2802- BOOST_FOREACH (const CTransaction &tx, block.vtx ) {
2803- // ignore validation errors in resurrected transactions
2804- list<CTransaction> removed;
2805- CValidationState stateDummy;
2806- if (tx.IsCoinBase () || !AcceptToMemoryPool (mempool, stateDummy, tx, false , NULL , true )) {
2807- mempool.removeRecursive (tx, removed);
2808- } else if (mempool.exists (tx.GetHash ())) {
2809- vHashUpdate.push_back (tx.GetHash ());
2810- }
2811- }
2812- // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have
2813- // no in-mempool children, which is generally not true when adding
2814- // previously-confirmed transactions back to the mempool.
2815- // UpdateTransactionsFromBlock finds descendants of any transactions in this
2816- // block that were added back and cleans up the mempool state.
2817- mempool.UpdateTransactionsFromBlock (vHashUpdate);
2803+
2804+ if (!fBare ) {
2805+ // Resurrect mempool transactions from the disconnected block.
2806+ std::vector<uint256> vHashUpdate;
2807+ BOOST_FOREACH (const CTransaction &tx, block.vtx ) {
2808+ // ignore validation errors in resurrected transactions
2809+ list<CTransaction> removed;
2810+ CValidationState stateDummy;
2811+ if (tx.IsCoinBase () || !AcceptToMemoryPool (mempool, stateDummy, tx, false , NULL , true )) {
2812+ mempool.removeRecursive (tx, removed);
2813+ } else if (mempool.exists (tx.GetHash ())) {
2814+ vHashUpdate.push_back (tx.GetHash ());
2815+ }
2816+ }
2817+ // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have
2818+ // no in-mempool children, which is generally not true when adding
2819+ // previously-confirmed transactions back to the mempool.
2820+ // UpdateTransactionsFromBlock finds descendants of any transactions in this
2821+ // block that were added back and cleans up the mempool state.
2822+ mempool.UpdateTransactionsFromBlock (vHashUpdate);
2823+ }
2824+
28182825 // Update chainActive and related variables.
28192826 UpdateTip (pindexDelete->pprev , chainparams);
28202827 // Let wallets know transactions went from 1-confirmed to
@@ -3266,6 +3273,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
32663273 pindexNew->nDataPos = pos.nPos ;
32673274 pindexNew->nUndoPos = 0 ;
32683275 pindexNew->nStatus |= BLOCK_HAVE_DATA;
3276+ if (IsWitnessEnabled (pindexNew->pprev , Params ().GetConsensus ())) {
3277+ pindexNew->nStatus |= BLOCK_OPT_WITNESS;
3278+ }
32693279 pindexNew->RaiseValidity (BLOCK_VALID_TRANSACTIONS);
32703280 setDirtyBlockIndex.insert (pindexNew);
32713281
@@ -4214,6 +4224,90 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
42144224 return true ;
42154225}
42164226
4227+ bool RewindBlockIndex (const CChainParams& params)
4228+ {
4229+ LOCK (cs_main);
4230+
4231+ int nHeight = 1 ;
4232+ while (nHeight <= chainActive.Height ()) {
4233+ if (IsWitnessEnabled (chainActive[nHeight - 1 ], params.GetConsensus ()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
4234+ break ;
4235+ }
4236+ nHeight++;
4237+ }
4238+
4239+ // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
4240+ CValidationState state;
4241+ CBlockIndex* pindex = chainActive.Tip ();
4242+ while (chainActive.Height () >= nHeight) {
4243+ if (fPruneMode && !(chainActive.Tip ()->nStatus & BLOCK_HAVE_DATA)) {
4244+ // If pruning, don't try rewinding past the HAVE_DATA point;
4245+ // since older blocks can't be served anyway, there's
4246+ // no need to walk further, and trying to DisconnectTip()
4247+ // will fail (and require a needless reindex/redownload
4248+ // of the blockchain).
4249+ break ;
4250+ }
4251+ if (!DisconnectTip (state, params, true )) {
4252+ return error (" RewindBlockIndex: unable to disconnect block at height %i" , pindex->nHeight );
4253+ }
4254+ // Occasionally flush state to disk.
4255+ if (!FlushStateToDisk (state, FLUSH_STATE_PERIODIC))
4256+ return false ;
4257+ }
4258+
4259+ // Reduce validity flag and have-data flags.
4260+ // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
4261+ // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
4262+ for (BlockMap::iterator it = mapBlockIndex.begin (); it != mapBlockIndex.end (); it++) {
4263+ CBlockIndex* pindexIter = it->second ;
4264+
4265+ // Note: If we encounter an insufficiently validated block that
4266+ // is on chainActive, it must be because we are a pruning node, and
4267+ // this block or some successor doesn't HAVE_DATA, so we were unable to
4268+ // rewind all the way. Blocks remaining on chainActive at this point
4269+ // must not have their validity reduced.
4270+ if (IsWitnessEnabled (pindexIter->pprev , params.GetConsensus ()) && !(pindexIter->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains (pindexIter)) {
4271+ // Reduce validity
4272+ pindexIter->nStatus = std::min<unsigned int >(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindexIter->nStatus & ~BLOCK_VALID_MASK);
4273+ // Remove have-data flags.
4274+ pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
4275+ // Remove storage location.
4276+ pindexIter->nFile = 0 ;
4277+ pindexIter->nDataPos = 0 ;
4278+ pindexIter->nUndoPos = 0 ;
4279+ // Remove various other things
4280+ pindexIter->nTx = 0 ;
4281+ pindexIter->nChainTx = 0 ;
4282+ pindexIter->nSequenceId = 0 ;
4283+ // Make sure it gets written.
4284+ setDirtyBlockIndex.insert (pindexIter);
4285+ // Update indexes
4286+ setBlockIndexCandidates.erase (pindexIter);
4287+ std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> ret = mapBlocksUnlinked.equal_range (pindexIter->pprev );
4288+ while (ret.first != ret.second ) {
4289+ if (ret.first ->second == pindexIter) {
4290+ mapBlocksUnlinked.erase (ret.first ++);
4291+ } else {
4292+ ++ret.first ;
4293+ }
4294+ }
4295+ } else if (pindexIter->IsValid (BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx ) {
4296+ setBlockIndexCandidates.insert (pindexIter);
4297+ }
4298+ }
4299+
4300+ PruneBlockIndexCandidates ();
4301+
4302+ CheckBlockIndex (params.GetConsensus ());
4303+
4304+ if (!FlushStateToDisk (state, FLUSH_STATE_ALWAYS)) {
4305+ return false ;
4306+ }
4307+
4308+ return true ;
4309+ }
4310+
42174311void UnloadBlockIndex ()
42184312{
42194313 LOCK (cs_main);
0 commit comments