Revert "utxosnapshot: v2 format — embed full blk0001.dat into snapshot"
This reverts commit 69529ea4c7.
This commit is contained in:
+14
-112
@@ -42,27 +42,20 @@ bool DumpSnapshot(const fs::path& destPath,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collect block index entries.
|
||||
// v2 always includes EVERY block from genesis to tip, so a node
|
||||
// loading this snapshot has full chain index (every block addressable
|
||||
// via mapBlockIndex + readable from blk0001.dat).
|
||||
// The nHeaders argument is honored only for legacy v1 generation.
|
||||
const bool includeAllBlocks = (nHeaders == 0 || nHeaders > (unsigned int)nBestHeight);
|
||||
// Collect block index entries (last nHeaders blocks, height ascending)
|
||||
std::vector<std::pair<uint256, CDiskBlockIndex>> vHeaders;
|
||||
vHeaders.reserve(nHeaders);
|
||||
{
|
||||
CBlockIndex* pindex = pindexBest;
|
||||
while (pindex) {
|
||||
unsigned int nCollected = 0;
|
||||
while (pindex && nCollected < nHeaders) {
|
||||
CDiskBlockIndex diskindex(pindex);
|
||||
vHeaders.push_back({*pindex->phashBlock, diskindex});
|
||||
pindex = pindex->pprev;
|
||||
nCollected++;
|
||||
}
|
||||
// Reverse to height ascending order (genesis first)
|
||||
// Reverse to height ascending order
|
||||
std::reverse(vHeaders.begin(), vHeaders.end());
|
||||
|
||||
// Legacy v1 path: trim to last nHeaders if requested and not already all
|
||||
if (!includeAllBlocks && vHeaders.size() > nHeaders) {
|
||||
vHeaders.erase(vHeaders.begin(), vHeaders.begin() + (vHeaders.size() - nHeaders));
|
||||
}
|
||||
}
|
||||
|
||||
// Open the chain DB once and reuse for both the UTXO count and the
|
||||
@@ -98,18 +91,6 @@ bool DumpSnapshot(const fs::path& destPath,
|
||||
int64_t moneySupply = pindexBest->nMoneySupply;
|
||||
unsigned int numHeaders = (unsigned int)vHeaders.size();
|
||||
unsigned int numUtxos = (unsigned int)nUtxoCount;
|
||||
// numBlocks = size of raw blk0001.dat content to embed in the snapshot.
|
||||
// We size this up front; the actual write below streams the file.
|
||||
unsigned int numBlocks = 0;
|
||||
{
|
||||
FILE* blkFile = fopen((GetDataDir() / "blk0001.dat").string().c_str(), "rb");
|
||||
if (blkFile) {
|
||||
fseek(blkFile, 0, SEEK_END);
|
||||
long blkSize = ftell(blkFile);
|
||||
fclose(blkFile);
|
||||
if (blkSize > 0) numBlocks = (unsigned int)blkSize;
|
||||
}
|
||||
}
|
||||
uint256 contentHash; // placeholder, filled after writing data
|
||||
|
||||
fwrite(&magic, sizeof(magic), 1, file);
|
||||
@@ -120,7 +101,6 @@ bool DumpSnapshot(const fs::path& destPath,
|
||||
fwrite(&moneySupply, sizeof(moneySupply), 1, file);
|
||||
fwrite(&numHeaders, sizeof(numHeaders), 1, file);
|
||||
fwrite(&numUtxos, sizeof(numUtxos), 1, file);
|
||||
fwrite(&numBlocks, sizeof(numBlocks), 1, file); // v2+: size of embedded blk0001.dat
|
||||
long contentHashPos = ftell(file);
|
||||
fwrite(&contentHash, sizeof(contentHash), 1, file); // placeholder
|
||||
|
||||
@@ -202,34 +182,6 @@ bool DumpSnapshot(const fs::path& destPath,
|
||||
}
|
||||
}
|
||||
|
||||
// v2: Append the raw blk0001.dat content so a fresh node is fully
|
||||
// self-contained. Streams in chunks; SHA256 covers the bytes.
|
||||
if (numBlocks > 0) {
|
||||
FILE* blkFile = fopen((GetDataDir() / "blk0001.dat").string().c_str(), "rb");
|
||||
if (!blkFile) {
|
||||
fclose(file);
|
||||
strError = "Cannot open blk0001.dat for snapshot embedding";
|
||||
return false;
|
||||
}
|
||||
printf("UtxoSnapshot: embedding blk0001.dat (%u bytes) into snapshot\n", numBlocks);
|
||||
unsigned char blkBuf[64 * 1024];
|
||||
size_t nLeft = numBlocks;
|
||||
while (nLeft > 0) {
|
||||
size_t nWant = nLeft > sizeof(blkBuf) ? sizeof(blkBuf) : nLeft;
|
||||
size_t nRead = fread(blkBuf, 1, nWant, blkFile);
|
||||
if (nRead != nWant) {
|
||||
fclose(blkFile);
|
||||
fclose(file);
|
||||
strError = "Short read on blk0001.dat during snapshot embed";
|
||||
return false;
|
||||
}
|
||||
fwrite(blkBuf, 1, nRead, file);
|
||||
SHA256_Update(&sha256, blkBuf, nRead);
|
||||
nLeft -= nRead;
|
||||
}
|
||||
fclose(blkFile);
|
||||
}
|
||||
|
||||
// Finalize content hash and write it to the header
|
||||
SHA256_Final((unsigned char*)&contentHash, &sha256);
|
||||
fseek(file, contentHashPos, SEEK_SET);
|
||||
@@ -237,8 +189,8 @@ bool DumpSnapshot(const fs::path& destPath,
|
||||
|
||||
fclose(file);
|
||||
|
||||
printf("UtxoSnapshot: wrote %s (%d headers, %d UTXOs, %u block bytes, hash=%s)\n",
|
||||
destPath.string().c_str(), numHeaders, numUtxos, numBlocks,
|
||||
printf("UtxoSnapshot: wrote %s (%d headers, %d UTXOs, hash=%s)\n",
|
||||
destPath.string().c_str(), numHeaders, numUtxos,
|
||||
contentHash.ToString().c_str());
|
||||
|
||||
return true;
|
||||
@@ -288,7 +240,7 @@ bool LoadSnapshot(const fs::path& snapshotPath,
|
||||
int height;
|
||||
uint256 blockHash;
|
||||
int64_t moneySupply;
|
||||
unsigned int numHeaders = 0, numUtxos = 0, numBlocks = 0;
|
||||
unsigned int numHeaders, numUtxos;
|
||||
uint256 expectedContentHash;
|
||||
|
||||
if (fread(&magic, sizeof(magic), 1, file) != 1 ||
|
||||
@@ -296,32 +248,12 @@ bool LoadSnapshot(const fs::path& snapshotPath,
|
||||
fread(&network, sizeof(network), 1, file) != 1 ||
|
||||
fread(&height, sizeof(height), 1, file) != 1 ||
|
||||
fread(&blockHash, sizeof(blockHash), 1, file) != 1 ||
|
||||
fread(&moneySupply, sizeof(moneySupply), 1, file) != 1) {
|
||||
fread(&moneySupply, sizeof(moneySupply), 1, file) != 1 ||
|
||||
fread(&numHeaders, sizeof(numHeaders), 1, file) != 1 ||
|
||||
fread(&numUtxos, sizeof(numUtxos), 1, file) != 1 ||
|
||||
fread(&expectedContentHash, sizeof(expectedContentHash), 1, file) != 1) {
|
||||
fclose(file);
|
||||
strError = "Truncated snapshot header (common fields)";
|
||||
return false;
|
||||
}
|
||||
if (fread(&numHeaders, sizeof(numHeaders), 1, file) != 1) {
|
||||
fclose(file);
|
||||
strError = "Truncated snapshot header (numHeaders)";
|
||||
return false;
|
||||
}
|
||||
if (fread(&numUtxos, sizeof(numUtxos), 1, file) != 1) {
|
||||
fclose(file);
|
||||
strError = "Truncated snapshot header (numUtxos)";
|
||||
return false;
|
||||
}
|
||||
// v2+ has numBlocks between numUtxos and contentHash. v1 stops here.
|
||||
if (version >= 2) {
|
||||
if (fread(&numBlocks, sizeof(numBlocks), 1, file) != 1) {
|
||||
fclose(file);
|
||||
strError = "Truncated snapshot header (numBlocks)";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fread(&expectedContentHash, sizeof(expectedContentHash), 1, file) != 1) {
|
||||
fclose(file);
|
||||
strError = "Truncated snapshot header (contentHash)";
|
||||
strError = "Truncated snapshot header";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -528,36 +460,6 @@ bool LoadSnapshot(const fs::path& snapshotPath,
|
||||
success = false;
|
||||
}
|
||||
|
||||
// v2: After UTXOs, extract the raw blk0001.dat content. This makes the
|
||||
// loaded node fully self-contained — no separate bootstrap needed.
|
||||
if (success && version >= 2 && numBlocks > 0) {
|
||||
printf("UtxoSnapshot: extracting %u block bytes to blk0001.dat...\n", numBlocks);
|
||||
fs::path blkOut = dataDir / "blk0001.dat";
|
||||
FILE* blkOutFile = fopen(blkOut.string().c_str(), "wb");
|
||||
if (!blkOutFile) {
|
||||
success = false;
|
||||
strError = "Cannot create blk0001.dat for snapshot extract: " + blkOut.string();
|
||||
} else {
|
||||
unsigned char blkBuf[64 * 1024];
|
||||
size_t nLeft = numBlocks;
|
||||
while (nLeft > 0 && success) {
|
||||
size_t nWant = nLeft > sizeof(blkBuf) ? sizeof(blkBuf) : nLeft;
|
||||
size_t nRead = fread(blkBuf, 1, nWant, file);
|
||||
if (nRead != nWant) {
|
||||
success = false;
|
||||
strError = "Short read on snapshot blocks section";
|
||||
break;
|
||||
}
|
||||
fwrite(blkBuf, 1, nRead, blkOutFile);
|
||||
SHA256_Update(&sha256, blkBuf, nRead);
|
||||
nLeft -= nRead;
|
||||
}
|
||||
fclose(blkOutFile);
|
||||
if (success)
|
||||
printf("UtxoSnapshot: wrote blk0001.dat (%u bytes)\n", numBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify content hash
|
||||
if (success) {
|
||||
uint256 actualHash;
|
||||
|
||||
+7
-26
@@ -11,46 +11,27 @@
|
||||
static const unsigned int UTXO_SNAPSHOT_MAGIC = 0x53585455; // "UTXS" little-endian
|
||||
|
||||
// UTXO snapshot format version
|
||||
//
|
||||
// v1: headers (last N=2000) + UTXOs only. Node still needs blk0001.dat from
|
||||
// somewhere (legacy bootstrap tarball or P2P) to fully verify.
|
||||
// v2: full chain archive. Adds a `blocks` section with raw blk0001.dat content
|
||||
// and writes ALL CDiskBlockIndex entries (every block from genesis to
|
||||
// snapshot tip). After loading a v2 snapshot, the node is fully
|
||||
// self-contained: it can serve any block to peers, fully verify the
|
||||
// chain, validate transactions, and resume syncing from the snapshot
|
||||
// tip forward. Replaces the legacy `tri-bootstrap.tar.gz` artifact.
|
||||
static const unsigned int UTXO_SNAPSHOT_VERSION = 2;
|
||||
static const unsigned int UTXO_SNAPSHOT_VERSION = 1;
|
||||
|
||||
// Number of block index entries to include in snapshot (v1 only).
|
||||
// v2 always includes ALL headers — this constant is retained for the v1
|
||||
// fallback path and as a CLI override for diagnostic snapshots.
|
||||
// Number of block index entries to include in snapshot (covers difficulty,
|
||||
// median time, stake modifier, and reorg depth requirements)
|
||||
static const unsigned int UTXO_SNAPSHOT_DEFAULT_HEADERS = 2000;
|
||||
|
||||
namespace UtxoSnapshot {
|
||||
|
||||
// Create a UTXO snapshot from the current chain state.
|
||||
// (v2) Writes ALL CDiskBlockIndex entries + the raw blk0001.dat bytes +
|
||||
// all UTXOs to destPath. Output is a complete chain archive at the
|
||||
// current tip — a fresh node loading this is fully usable (can serve
|
||||
// blocks, fully verify, sync forward).
|
||||
// Writes last nHeaders block index entries + all UTXOs to destPath.
|
||||
// Returns true on success, sets strError on failure.
|
||||
bool DumpSnapshot(const std::filesystem::path& destPath,
|
||||
unsigned int nHeaders,
|
||||
std::string& strError);
|
||||
|
||||
// Load a UTXO snapshot from a file into the data directory.
|
||||
// Writes:
|
||||
// - all CDiskBlockIndex entries → chain DB
|
||||
// - all UTXOs → chain DB
|
||||
// - raw blk0001.dat bytes → dataDir/blk0001.dat
|
||||
// - hashBestChain, dbformat → chain DB
|
||||
// The chain DB must NOT be open yet (call before LoadBlockIndex).
|
||||
// Load a UTXO snapshot from a file into a fresh LevelDB.
|
||||
// Writes block index entries, UTXOs, hashBestChain, and dbformat.
|
||||
// The LevelDB must NOT be open yet (call before LoadBlockIndex).
|
||||
// `requireCheckpoint` enforces that the snapshot tip is a known
|
||||
// checkpoint (for P2P-delivered snapshots). Local loads from a
|
||||
// trusted operator pass false.
|
||||
// v1 snapshots (headers+UTXOs only) still load via the partial-load
|
||||
// path; the blocks section is simply absent.
|
||||
// Returns true on success, sets strError on failure.
|
||||
bool LoadSnapshot(const std::filesystem::path& snapshotPath,
|
||||
const std::filesystem::path& dataDir,
|
||||
|
||||
Reference in New Issue
Block a user