From e2d4207e89c3054f42e09fdeeb61bd35c1fc6ad2 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 4 Nov 2026 05:32:18 +0000 Subject: [PATCH 1/2] fix(index): don't rewind blocks the index has already indexed An eager index (address, spent, timestamp) resumes from its uncommitted tip after an unclean stop, which is above the restored active tip. The blocks in between are often left with only their headers in the block index, because headers are stored before block data and the block index is written hourly while coins flush daily. When the node connects the first of them again, BlockConnected() saw a block below the index tip and rewound the index to its parent. That reads every block up to the uncommitted tip from disk, which fails while they are still being downloaded again, so the node stopped with a fatal error, and the next start can fail the same way. A connected block that is an ancestor of the index's best block is already indexed, so skip it. This also stops queued notifications that arrive after the sync thread caught up from rewinding and re-appending blocks the sync already indexed. The test index now reads each block it rewinds, as the address and spent indexes do, so the test fails without this change. Co-Authored-By: Claude Opus 5.5 --- src/index/base.cpp | 5 +++++ src/test/baseindex_tests.cpp | 43 ++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/index/base.cpp b/src/index/base.cpp index 7c9b9056b2ce..a02eef22f876 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -401,6 +401,11 @@ void BaseIndex::BlockConnected(const std::shared_ptr& block, const best_block_index->GetBlockHash().ToString()); return; } + // Init() can resume from an uncommitted tip above the active chain. The blocks below it are indexed already, + // and after an unclean stop their data may not be on disk again yet, so they can't be rewound. + if (best_block_index->GetAncestor(pindex->nHeight) == pindex) { + return; + } if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) { FatalError("%s: Failed to rewind index %s to a previous chain tip", __func__, GetName()); diff --git a/src/test/baseindex_tests.cpp b/src/test/baseindex_tests.cpp index 68c1d63a7704..599661989c0e 100644 --- a/src/test/baseindex_tests.cpp +++ b/src/test/baseindex_tests.cpp @@ -3,12 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include #include #include +#include #include