Merge pull request #15 from SamiAhmed7777/audit/sync-fast-assumevalid

main: extend assumeValid fast path past hardcoded checkpoints
This commit is contained in:
SamiAhmed7777
2026-07-07 13:32:43 -07:00
committed by GitHub
2 changed files with 50 additions and 4 deletions
+41 -4
View File
@@ -75,6 +75,14 @@ uint256 nBestInvalidTrust = 0;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = nullptr;
CBlockIndex* pindexFinalized = nullptr; // auto-checkpoint: deepest finalized block
// nAssumeValidThreshold: highest block height covered by the assumeValid
// fast path. The fast path skips sigops/script/UTXO validation for blocks
// at or below this height (we've already verified the chain up to here).
// Initially 0 (only hardcoded checkpoints trigger fast path). Advances by
// ASSUME_VALID_BUFFER blocks BEHIND the tip after each successful SetBestChain.
// Persisted via wallet DB so a restart doesn't re-validate 2.2M blocks.
int nAssumeValidThreshold = 0;
bool fAddressIndex = false;
int64_t nTimeBestReceived = 0;
@@ -2173,10 +2181,19 @@ bool CBlock::ConnectBlock(CTxDBBase& txdb, CBlockIndex* pindex, bool fJustCheck)
if (!CheckBlock(!fJustCheck, !fJustCheck, false))
return false;
// Determine if this block is covered by the hardcoded checkpoint.
// Below checkpoint: skip all input validation, FetchInputs, ConnectInputs,
// and wallet sync. The checkpoint hash guarantees chain integrity for these blocks.
bool fAssumeValid = (pindex->nHeight <= Checkpoints::GetTotalBlocksEstimate());
// Determine if this block is covered by the hardcoded checkpoint or
// our rolling assumeValid threshold. Below either: skip all input
// validation, FetchInputs, ConnectInputs, and wallet sync. Trust
// comes from either the static checkpoint map (compile-time, signed
// hashes baked into the binary) OR our own prior validation history
// (nAssumeValidThreshold, advanced after each successful connect).
//
// For the rolling threshold: only the last ASSUME_VALID_BUFFER blocks
// are fully validated every time. Everything older takes the fast
// path because we've already connected it successfully. A reorg that
// tries to rewrite within the buffer is caught by full validation.
bool fAssumeValid = (pindex->nHeight <= Checkpoints::GetTotalBlocksEstimate())
|| (pindex->nHeight <= nAssumeValidThreshold);
bool fIsInitialDownload = IsInitialBlockDownload();
//// issue here: it doesn't know the version
@@ -2835,6 +2852,26 @@ bool CBlock::SetBestChain(CTxDBBase& txdb, CBlockIndex* pindexNew)
}
}
// Rolling assumeValid threshold: advance so blocks older than
// ASSUME_VALID_BUFFER from the tip take the fast path on future
// connects. We do this AFTER the finality checkpoint update so the
// fast-path boundary always lags the finality boundary by at least
// ASSUME_VALID_BUFFER — no gap, no overlap risk on reorgs.
//
// Only advance when fully synced. During IBD we want full validation
// until we're confident the chain is correct, then we can lean on
// prior validation history.
if (!IsInitialBlockDownload() && nBestHeight > (int)ASSUME_VALID_BUFFER)
{
int newThreshold = nBestHeight - (int)ASSUME_VALID_BUFFER;
if (newThreshold > nAssumeValidThreshold)
{
nAssumeValidThreshold = newThreshold;
printf("ASSUME-VALID: threshold advanced to block %d (full validation only for last %d blocks)\n",
nAssumeValidThreshold, ASSUME_VALID_BUFFER);
}
}
uint256 nBestBlockTrust = (pindexBest->nHeight != 0 && pindexBest->pprev) ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
// Log every 5000 blocks during sync, every block once caught up
+9
View File
@@ -43,6 +43,14 @@ constexpr unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
constexpr unsigned int MAX_ORPHAN_BLOCKS = 750;
constexpr unsigned int MAX_ORPHAN_BLOCKS_IBD = 1500;
constexpr unsigned int MAX_REORG_DEPTH = 100; // reject reorgs deeper than this (finality)
// ASSUME_VALID_BUFFER: how many blocks BACK from the tip to keep fully
// validating. Blocks at or below nAssumeValidThreshold take the fast path
// (skip sigops/script/UTXO validation) because we've already verified the
// entire chain up to that height. We always validate the last BUFFER blocks
// so a reorg attack that rewrites the top of the chain is caught immediately.
// Lower = safer, higher = faster sync.
constexpr unsigned int ASSUME_VALID_BUFFER = 100;
constexpr unsigned int MAX_INV_SZ = 50000;
constexpr int64_t MIN_TX_FEE = (1 * CENT) / 100;
constexpr int64_t MIN_RELAY_TX_FEE = (1 * CENT) / 100;
@@ -89,6 +97,7 @@ extern uint256 nBestInvalidTrust;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern CBlockIndex* pindexFinalized; // auto-checkpoint: deepest finalized block
extern int nAssumeValidThreshold; // highest height covered by assumeValid fast path
extern unsigned int nTransactionsUpdated;
extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockSize;