fix(bootstrap): keep the archive unless a checksum truly mismatches

Any verification failure deleted the downloaded archive and forced a
full multi-GB re-download on the next attempt. But most failures are not
a corrupt archive: a missing or unreadable checksum sidecar, or a fetch
blip while pulling the checksum, would throw away a perfectly good file.
On top of that the checksum parser took the first token of whatever came
back, so an HTTP error page could be mistaken for a digest.

- The archive is now removed only on a genuine digest mismatch. A
  missing sidecar, an unusable one, or a transient fetch error keeps the
  file so the next attempt can reuse or resume it; the no-checksum case
  still fails closed and keeps the archive.
- The checksum parser now accepts a token only if it is exactly the
  expected length and all hex, lowercasing it; anything else (an error
  page, a truncated or wrong-width digest) is rejected.
- The small-file fetch moved onto the shared capped HTTP helper, and MD5
  is consulted only as a fallback when no SHA-256 is published.

Tests cover the checksum parser across good, wrong-length, non-hex, and
error-page inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 20:57:21 -05:00
co-authored by Claude Opus 4.8
parent b3a1a9e654
commit 4d9d528566
3 changed files with 68 additions and 118 deletions
+16
View File
@@ -3946,6 +3946,21 @@ static void plantOldBootstrapChain(const fs::path& data, const std::string& wall
{ std::ofstream f(data / "wallet.dat", std::ios::binary); f.write(walletBytes.data(), (std::streamsize)walletBytes.size()); }
}
void testBootstrapParseChecksum()
{
using dragonx::util::Bootstrap;
const std::string h64(64, 'a'), h32(32, 'b');
EXPECT_EQ(Bootstrap::parseChecksumFile(h64 + " DRAGONX.zip", 64), h64);
{ std::string up(64, 'A'); EXPECT_EQ(Bootstrap::parseChecksumFile(up, 64), std::string(64, 'a')); }
EXPECT_EQ(Bootstrap::parseChecksumFile("<!DOCTYPE html><html>...", 64), std::string());
EXPECT_EQ(Bootstrap::parseChecksumFile(std::string(63, 'a'), 64), std::string());
EXPECT_EQ(Bootstrap::parseChecksumFile(std::string(65, 'a'), 64), std::string());
{ std::string bad(63, 'a'); bad += 'g'; EXPECT_EQ(Bootstrap::parseChecksumFile(bad, 64), std::string()); }
EXPECT_EQ(Bootstrap::parseChecksumFile(h32, 32), h32);
EXPECT_EQ(Bootstrap::parseChecksumFile(h32, 64), std::string());
EXPECT_EQ(Bootstrap::parseChecksumFile("", 64), std::string());
}
void testBootstrapSpaceSufficient()
{
using dragonx::util::Bootstrap;
@@ -18432,6 +18447,7 @@ int main()
testResourceNeedsWrite();
testXmrigProvisionPolicy();
testBootstrapSpaceSufficient();
testBootstrapParseChecksum();
testBootstrapPlanArchive();
#ifndef _WIN32
testBootstrapReclaimable();