Merge origin/master (Krystie's RocksDB+IBD integration + snapshot wiring)
Reconciles two parallel implementations of multi-backend chain DB: local kept its MakeChainDB factory + std::filesystem + unconditional RocksDB + abstracted utxosnapshot, since those are downstream of the boost-cleanup, smessage-RocksDB-port, and CTxDBBase abstraction work. Preserved from origin (Krystie's branch): - Block 2,203,594 checkpoint and matching mapSnapshotHashes entry for P2P snapshot verification (src/checkpoints.cpp) - Headers-first IBD stall-recovery path: during IBD, replace the legacy PushGetBlocks fallback with RequestHeaderSyncRefillAllPeers + QueueHeaderSyncBlocksParallel so a stall on a weak peer set doesn't park at a low common ancestor (src/main.cpp SendMessages) Discarded from origin: - src/txdb.cpp (CActiveTxDB wrapper) — superseded by txdb-factory.cpp - BUILD_ROCKSDB-gated paths and inline LevelDB+RocksDB code in utxosnapshot.cpp — already factored out behind CTxDBBase - Public ReadRawBytes/WriteRawBytes/... wrappers added to CTxDBBase for CActiveTxDB; no remaining callers - GetActiveChainDbDirName / UseRocksDbBackend in bootstrap.cpp; switched to GetChainDataDir() Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+10
-8
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "utxosnapshot.h"
|
||||
#include "txdb.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
@@ -718,16 +719,16 @@ bool DownloadBootstrap(const std::string& host,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the archive included a trusted pre-built index (txleveldb/)
|
||||
// with a valid snapshot.manifest. If verified, keep it to skip the
|
||||
// Check if the archive included a trusted pre-built index for the active
|
||||
// backend with a valid snapshot.manifest. If verified, keep it to skip the
|
||||
// multi-hour FastImportBlockFile() rebuild.
|
||||
fs::path txleveldb = dataDir / "txleveldb";
|
||||
fs::path chainDbPath = GetChainDataDir();
|
||||
fs::path database = dataDir / "database";
|
||||
fs::path manifestPath = dataDir / "snapshot.manifest";
|
||||
|
||||
bool keepIndex = false;
|
||||
|
||||
if (fs::exists(manifestPath) && fs::exists(txleveldb)) {
|
||||
if (fs::exists(manifestPath) && fs::exists(chainDbPath)) {
|
||||
SnapshotManifest manifest;
|
||||
std::string manifestError;
|
||||
|
||||
@@ -754,9 +755,10 @@ bool DownloadBootstrap(const std::string& host,
|
||||
if (!keepIndex) {
|
||||
// No valid manifest or verification failed - delete the index.
|
||||
// FastImportBlockFile() will rebuild from blk0001.dat on next startup.
|
||||
printf("Bootstrap: removing extracted txleveldb/ (will rebuild index from blk0001.dat)\n");
|
||||
if (fs::exists(txleveldb))
|
||||
fs::remove_all(txleveldb);
|
||||
printf("Bootstrap: removing extracted %s/ (will rebuild index from blk0001.dat)\n",
|
||||
GetChainDataDir().filename().string().c_str());
|
||||
if (fs::exists(chainDbPath))
|
||||
fs::remove_all(chainDbPath);
|
||||
}
|
||||
|
||||
// Always remove BDB database/ dir (wallet environment from another machine)
|
||||
@@ -791,7 +793,7 @@ bool DownloadUtxoSnapshot(const std::string& host,
|
||||
|
||||
printf("Bootstrap: UTXO snapshot downloaded, loading into database...\n");
|
||||
|
||||
// Load the snapshot into a fresh txleveldb
|
||||
// Load the snapshot into a fresh active chain DB
|
||||
if (!UtxoSnapshot::LoadSnapshot(tmpPath, dataDir, strError)) {
|
||||
fs::remove(tmpPath);
|
||||
return false;
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ namespace Checkpoints
|
||||
{2200000, uint256("0x0a8d0442f031f1258120f713f34e45f4f9a625fb753558e27b89b32ad5a9a740")},
|
||||
{2205000, uint256("0xf7aa893ec012181e321783d6a5487addf6997377908faa3e760c9054a4217d29")},
|
||||
{2206000, uint256("0x780ae878f8b10b6cbd51ceb2c0799c90d3551fa916be62974375071b9e36581c")},
|
||||
{2203594, uint256("0x5e016ae5d1f163c6679292b717a3db467a39d24b0a315182f4783caa79c722d8")},
|
||||
{2207000, uint256("0x8836d67b0f08036c4a7c26ff0a29d4461a52b6d8f552165ad9c1abec2f3cadfd")},
|
||||
};
|
||||
|
||||
@@ -50,7 +51,7 @@ namespace Checkpoints
|
||||
// here. The corresponding (height, blockhash) must already exist in
|
||||
// mapCheckpoints / mapCheckpointsTestnet.
|
||||
static std::map<int, uint256> mapSnapshotHashes = {
|
||||
// {2186940, uint256("0x...sha256-of-utxo-snapshot.bin...")},
|
||||
{2203594, uint256("0x49b35dd01659975c4a31954f37174c6e2e8878dd0723ab306ccecd991c80f79a")},
|
||||
};
|
||||
|
||||
static std::map<int, uint256> mapSnapshotHashesTestnet = {
|
||||
|
||||
+47
-16
@@ -5994,24 +5994,55 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
(int)pto->mapAskFor.size());
|
||||
nLastStallLog = GetTime();
|
||||
}
|
||||
// Use the walk-forward progress point if available, to avoid
|
||||
// restarting from pindexBest (which hits the CBlockLocator
|
||||
// exponential gap and starts the walk-forward from scratch).
|
||||
pto->pindexLastGetBlocksBegin = NULL;
|
||||
if (nHighestInvWalk > nBestHeight && hashHighestInvWalk != 0 &&
|
||||
mapBlockIndex.count(hashHighestInvWalk))
|
||||
// During IBD, avoid falling back to legacy getblocks recovery
|
||||
// anchored at pindexBest or a stale inv walk point. That path can
|
||||
// repeatedly resolve the locator to the same low common ancestor
|
||||
// on a weak peer set, which looks like a sync "freeze" near an
|
||||
// early height even though the real bug is the recovery loop.
|
||||
// Keep stall recovery header-driven instead so the planner tip
|
||||
// advances from the newest known header state.
|
||||
if (IsInitialBlockDownload())
|
||||
{
|
||||
pto->PushGetBlocks(mapBlockIndex[hashHighestInvWalk], uint256(0));
|
||||
printf("SYNC-DIAG: stall re-request from walk=%d (not best=%d)\n",
|
||||
nHighestInvWalk, nBestHeight);
|
||||
} else {
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
pto->pindexLastGetHeadersBegin = NULL;
|
||||
|
||||
uint256 hashLocatorTip = hashBestHeaderSync;
|
||||
if (hashLocatorTip == 0 && nHighestInvWalk > nBestHeight &&
|
||||
hashHighestInvWalk != 0 && mapBlockIndex.count(hashHighestInvWalk))
|
||||
{
|
||||
hashLocatorTip = hashHighestInvWalk;
|
||||
}
|
||||
|
||||
unsigned int nRefilled = RequestHeaderSyncRefillAllPeers(
|
||||
hashLocatorTip,
|
||||
0,
|
||||
"stall-recovery");
|
||||
unsigned int nQueued = QueueHeaderSyncBlocksParallel(HEADER_DOWNLOAD_WINDOW);
|
||||
|
||||
printf("SYNC-DIAG: stall recovery used headers-first path (locator=%s, refillPeers=%u, queued=%u)\n",
|
||||
hashLocatorTip.ToString().substr(0,20).c_str(),
|
||||
nRefilled,
|
||||
nQueued);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outside IBD, preserve the older walk-forward getblocks
|
||||
// behavior since we're no longer building out a header planner.
|
||||
pto->pindexLastGetBlocksBegin = NULL;
|
||||
if (nHighestInvWalk > nBestHeight && hashHighestInvWalk != 0 &&
|
||||
mapBlockIndex.count(hashHighestInvWalk))
|
||||
{
|
||||
pto->PushGetBlocks(mapBlockIndex[hashHighestInvWalk], uint256(0));
|
||||
printf("SYNC-DIAG: stall re-request from walk=%d (not best=%d)\n",
|
||||
nHighestInvWalk, nBestHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
}
|
||||
|
||||
pto->pindexLastGetHeadersBegin = NULL;
|
||||
pto->PushGetHeaders(pindexBest, uint256(0));
|
||||
}
|
||||
// Also send getheaders during stall to restart the header planner.
|
||||
// Without this, a drained header cache stays empty because only
|
||||
// getblocks is sent on stall, which can't refill mapHeaderSync.
|
||||
pto->pindexLastGetHeadersBegin = NULL;
|
||||
pto->PushGetHeaders(pindexBest, uint256(0));
|
||||
nLastBlockReceived = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user