diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 43d5dd46208..3ba89d08d98 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2683,6 +2683,23 @@ public: }; }; +/** + * RAII class that temporarily rolls back the local chain in it's constructor + * and rolls it forward again in it's destructor. + */ +class TemporaryRollback +{ + ChainstateManager& m_chainman; + const CBlockIndex& m_invalidate_index; +public: + TemporaryRollback(ChainstateManager& chainman, const CBlockIndex& index) : m_chainman(chainman), m_invalidate_index(index) { + InvalidateBlock(m_chainman, m_invalidate_index.GetBlockHash()); + }; + ~TemporaryRollback() { + ReconsiderBlock(m_chainman, m_invalidate_index.GetBlockHash()); + }; +}; + /** * Serialize the UTXO set to a file for loading elsewhere. * @@ -2770,6 +2787,7 @@ static RPCHelpMan dumptxoutset() CConnman& connman = EnsureConnman(node); const CBlockIndex* invalidate_index{nullptr}; std::unique_ptr disable_network; + std::unique_ptr temporary_rollback; // If the user wants to dump the txoutset of the current tip, we don't have // to roll back at all @@ -2798,7 +2816,7 @@ static RPCHelpMan dumptxoutset() } invalidate_index = WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Next(target_index)); - InvalidateBlock(*node.chainman, invalidate_index->GetBlockHash()); + temporary_rollback = std::make_unique(*node.chainman, *invalidate_index); } Chainstate* chainstate; @@ -2822,23 +2840,15 @@ static RPCHelpMan dumptxoutset() // sister block of invalidate_index. This block (or a descendant) would // be activated as the new tip and we would not get to new_tip_index. if (target_index != chainstate->m_chain.Tip()) { - LogInfo("Failed to roll back to requested height, reverting to tip.\n"); - error = JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height."); + LogWarning("dumptxoutset failed to roll back to requested height, reverting to tip.\n"); + throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height."); } else { std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(*chainstate, node.rpc_interruption_point); } } - if (error.isNull()) { - result = WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile, path, temppath, node.rpc_interruption_point); - fs::rename(temppath, path); - } - if (invalidate_index) { - ReconsiderBlock(*node.chainman, invalidate_index->GetBlockHash()); - } - if (!error.isNull()) { - throw error; - } + result = WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile, path, temppath, node.rpc_interruption_point); + fs::rename(temppath, path); result.pushKV("path", path.utf8string()); return result;