Disconnect m_chain's tip. * After calling, the mempool will be in an inconsistent state, with * transactions from disconnected blocks being added to disconnectpool. You * should make the mempool consistent again by calling MaybeUpdateMempoolForReorg. * with cs_main held. * * If disconnectpool is nullptr, then no disconnected transactions are added to * disconnectpool (note that the
| 2941 | * in any case). |
| 2942 | */ |
| 2943 | bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool) |
| 2944 | { |
| 2945 | AssertLockHeld(cs_main); |
| 2946 | if (m_mempool) AssertLockHeld(m_mempool->cs); |
| 2947 | |
| 2948 | CBlockIndex *pindexDelete = m_chain.Tip(); |
| 2949 | assert(pindexDelete); |
| 2950 | assert(pindexDelete->pprev); |
| 2951 | // Read block from disk. |
| 2952 | std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); |
| 2953 | CBlock& block = *pblock; |
| 2954 | if (!m_blockman.ReadBlock(block, *pindexDelete)) { |
| 2955 | LogError("DisconnectTip(): Failed to read block\n"); |
| 2956 | return false; |
| 2957 | } |
| 2958 | // Apply the block atomically to the chain state. |
| 2959 | const auto time_start{SteadyClock::now()}; |
| 2960 | { |
| 2961 | CCoinsViewCache view(&CoinsTip()); |
| 2962 | assert(view.GetBestBlock() == pindexDelete->GetBlockHash()); |
| 2963 | if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK) { |
| 2964 | LogError("DisconnectTip(): DisconnectBlock %s failed\n", pindexDelete->GetBlockHash().ToString()); |
| 2965 | return false; |
| 2966 | } |
| 2967 | view.Flush(/*reallocate_cache=*/false); // local CCoinsViewCache goes out of scope |
| 2968 | } |
| 2969 | LogDebug(BCLog::BENCH, "- Disconnect block: %.2fms\n", |
| 2970 | Ticks<MillisecondsDouble>(SteadyClock::now() - time_start)); |
| 2971 | |
| 2972 | { |
| 2973 | // Prune locks that began at or after the tip should be moved backward so they get a chance to reorg |
| 2974 | const int max_height_first{pindexDelete->nHeight - 1}; |
| 2975 | for (auto& prune_lock : m_blockman.m_prune_locks) { |
| 2976 | if (prune_lock.second.height_first <= max_height_first) continue; |
| 2977 | |
| 2978 | prune_lock.second.height_first = max_height_first; |
| 2979 | LogDebug(BCLog::PRUNE, "%s prune lock moved back to %d\n", prune_lock.first, max_height_first); |
| 2980 | } |
| 2981 | } |
| 2982 | |
| 2983 | // Write the chain state to disk, if necessary. |
| 2984 | if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) { |
| 2985 | return false; |
| 2986 | } |
| 2987 | |
| 2988 | if (disconnectpool && m_mempool) { |
| 2989 | // Save transactions to re-add to mempool at end of reorg. If any entries are evicted for |
| 2990 | // exceeding memory limits, remove them and their descendants from the mempool. |
| 2991 | for (auto&& evicted_tx : disconnectpool->AddTransactionsFromBlock(block.vtx)) { |
| 2992 | m_mempool->removeRecursive(*evicted_tx, MemPoolRemovalReason::REORG); |
| 2993 | } |
| 2994 | } |
| 2995 | |
| 2996 | m_chain.SetTip(*pindexDelete->pprev); |
| 2997 | m_chainman.UpdateIBDStatus(); |
| 2998 | |
| 2999 | UpdateTip(pindexDelete->pprev); |
| 3000 | // Let wallets know transactions went from 1-confirmed to |