diff --git a/src/bootstrap.cpp b/src/bootstrap.cpp index 11a3a8b..c26b51f 100644 --- a/src/bootstrap.cpp +++ b/src/bootstrap.cpp @@ -52,7 +52,7 @@ bool NeedsBootstrap(const fs::path& dataDir) { // Need bootstrap if there's no chain database (the UTXO set / block index). // blk0001.dat alone is NOT sufficient — it's raw block data that requires - // FastImport to build an index, and FastImport is disabled by default. + // (fast-import was removed; UTXO snapshot is the only sync path) // Check for both LevelDB (txleveldb/) and RocksDB (chainstate/) backends. bool hasChainDb = fs::exists(dataDir / "txleveldb") || fs::exists(dataDir / "blocks" / "chainstate") @@ -734,7 +734,7 @@ bool DownloadBootstrap(const std::string& host, // 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. + // multi-hour rebuild (fast-import removed; UTXO snapshot is the only sync path). fs::path chainDbPath = GetChainDataDir(); fs::path database = dataDir / "database"; fs::path manifestPath = dataDir / "snapshot.manifest"; @@ -767,7 +767,7 @@ 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. + // The block index will be rebuilt from the UTXO snapshot on next startup. printf("Bootstrap: removing extracted %s/ (will rebuild index from blk0001.dat)\n", GetChainDataDir().filename().string().c_str()); if (fs::exists(chainDbPath)) diff --git a/src/init.cpp b/src/init.cpp index 8faad44..819a610 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -533,7 +533,6 @@ std::string HelpMessage() " -seedurl= " + _("HTTP seed list host (default: seeds.cryptographic-triangles.org)") + "\n" + " -noseedurl " + _("Disable HTTP seed list fetch on startup") + "\n" + " -autorerebuild= " + _("If our chain is more than blocks behind peers, wipe chain DB and shutdown for clean restart (default: 0=disabled)") + "\n" + - " -allowfastimport " + _("Permit FastImport as fallback (operator opt-in only; default off)") + "\n" + " -banscore= " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -bantime= " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + " -par= " + _("Set the number of script verification threads (default: auto, 0 = auto, 1 = single-threaded)") + "\n" + @@ -1160,7 +1159,7 @@ bool AppInit2() } // Handle -reindex: delete the chain DB so it gets rebuilt from the raw - // blk*.dat files via FastImportBlockFile(). This recalculates money + // blk*.dat files. This recalculates money // supply, tx index, and UTXO set from scratch. Backend-agnostic via // WipeChainDataDir(), which resolves the directory per the configured // -chaindb backend. @@ -1209,38 +1208,15 @@ bool AppInit2() } // AutoRebuild: if -autorerebuild is set and we are behind peers, wipe chain DB - // and shutdown for clean restart. Must run before FastImportBlockFile below. + // and shutdown for clean restart. MaybeAutoRebuild(GetArg("-autorerebuild", 0)); if (fRequestShutdown) { printf("AutoRebuild: shutdown requested before chain load complete\n"); return false; } - // If the block index is empty but blk0001.dat exists (bootstrap download), - // fast-import would normally rebuild from the block file. Per Sami: FastImport - // is REMOVED as a primary path — the UTXO snapshot is the canonical sync start. - // FastImport is gated behind -allowfastimport for explicit operator opt-in only - // (emergency recovery, snapshot format incompatibility, etc). - if (nBestHeight == 0 && std::filesystem::exists(GetDataDir() / "blk0001.dat") - && mapBlockIndex.size() <= 1) - { - if (!GetBoolArg("-allowfastimport", false)) - { - printf("FastImport: blk0001.dat present but -allowfastimport not set — " - "ignoring block file, will sync from network via UTXO snapshot.\n"); - // Remove the stale blk0001.dat so it doesn't trigger again - std::filesystem::remove(GetDataDir() / "blk0001.dat"); - } - else - { - printf("FastImport: WARNING -allowfastimport is set; rebuilding from local blk0001.dat.\n"); - uiInterface.InitMessage(_("Importing bootstrap blocks...")); - printf("Block index empty but blk0001.dat exists - running fast import...\n"); - int64_t nFastImportStart = GetTimeMillis(); - FastImportBlockFile(); - StartupPerfLog("bootstrap_fast_import", GetTimeMillis() - nFastImportStart, strprintf("bestheight=%d", nBestHeight)); - } - } + // Block index loaded. With fast-import removed, the only supported sync path + // is the UTXO snapshot (auto-downloaded from bootstrap or placed manually in datadir). // as LoadBlockIndex can take several minutes, it's possible the user // requested to kill triangles-qt during the last operation. If so, exit. diff --git a/src/main.cpp b/src/main.cpp index 69318cb..48c5a60 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3641,287 +3641,11 @@ bool LoadExternalBlockFile(FILE* fileIn) return nLoaded > 0; } -bool FastImportBlockFile() -{ - // Fast block import: reads blk0001.dat and builds the block index - // directly without re-writing block data. LevelDB writes are batched - // every 200K blocks for speed. Only used for trusted bootstrap data - // (blocks below the hardcoded checkpoint). - - fs::path blkPath = GetDataDir() / "blk0001.dat"; - if (!fs::exists(blkPath)) - return false; - - printf("FastImportBlockFile: starting from %s\n", blkPath.string().c_str()); - int64_t nStart = GetTimeMillis(); - - FILE* fileIn = fopen(blkPath.string().c_str(), "rb"); - if (!fileIn) - return false; - - // Get file size for progress - fseek(fileIn, 0, SEEK_END); - int64_t nFileSize = ftell(fileIn); - fseek(fileIn, 0, SEEK_SET); - - int nLoaded = 0; - int64_t nLastProgressReport = 0; - - { - LOCK(cs_main); - CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION); - - auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; - txdb.TxnBegin(); - - unsigned int nPos = 0; - while (nPos != (unsigned int)-1 && blkdat.good() && !fRequestShutdown) - { - // Find message start bytes (same scan as LoadExternalBlockFile) - unsigned char pchData[65536]; - do { - fseek(blkdat, nPos, SEEK_SET); - int nRead = fread(pchData, 1, sizeof(pchData), blkdat); - if (nRead <= 8) - { - nPos = (unsigned int)-1; - break; - } - void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart)); - if (nFind) - { - if (memcmp(nFind, pchMessageStart, sizeof(pchMessageStart))==0) - { - nPos += ((unsigned char*)nFind - pchData) + sizeof(pchMessageStart); - break; - } - nPos += ((unsigned char*)nFind - pchData) + 1; - } - else - nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1; - } while(!fRequestShutdown); - - if (nPos == (unsigned int)-1) - break; - - fseek(blkdat, nPos, SEEK_SET); - unsigned int nSize; - blkdat >> nSize; - - if (nSize == 0 || nSize > MAX_BLOCK_SIZE) - { - nPos += 4 + nSize; - continue; - } - - // nBlockPos = file position where the block data starts - // (after 4-byte message start + 4-byte size) - unsigned int nBlockPos = nPos + 4; - - CBlock block; - blkdat >> block; - - uint256 hash = block.GetHash(); - if (mapBlockIndex.count(hash)) - { - nPos += 4 + nSize; - continue; // already indexed - } - - // Create CBlockIndex - CBlockIndex* pindexNew = new CBlockIndex(1, nBlockPos, block); - if (!pindexNew) - break; - - // Link to previous block - auto miPrev = mapBlockIndex.find(block.hashPrevBlock); - if (miPrev != mapBlockIndex.end()) - { - pindexNew->pprev = miPrev->second; - pindexNew->nHeight = pindexNew->pprev->nHeight + 1; - } - - // Chain trust - pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust(); - - // Stake entropy bit - pindexNew->SetStakeEntropyBit(block.GetStakeEntropyBit()); - - // Stake modifier (minimal for blocks far below checkpoint) - int nCheckpointHeight = Checkpoints::GetTotalBlocksEstimate(); - if (pindexNew->nHeight >= nCheckpointHeight - 1000) - { - uint64_t nStakeModifier = 0; - bool fGeneratedStakeModifier = false; - ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier); - pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); - } - else - { - pindexNew->SetStakeModifier(0, pindexNew->nHeight == 0); - } - pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); - - // PoS stake seen set - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - - // Insert into mapBlockIndex - auto mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &mi->first; - - // Link pnext for previous block - if (pindexNew->pprev) - pindexNew->pprev->pnext = pindexNew; - - // Build tx index + UTXO entries, tracking money supply - int64_t nBlockValueIn = 0; - int64_t nBlockValueOut = 0; - int64_t nFees = 0; - unsigned int nTxPos = nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(block.vtx.size()); - for (size_t nTxIdx = 0; nTxIdx < block.vtx.size(); nTxIdx++) - { - const CTransaction& tx = block.vtx[nTxIdx]; - uint256 hashTx = tx.GetHash(); - CDiskTxPos posThisTx(1, nBlockPos, nTxPos); - txdb.UpdateTxIndex(hashTx, CTxIndex(posThisTx, tx.vout.size())); - nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); - - int64_t nTxValueOut = tx.GetValueOut(); - nBlockValueOut += nTxValueOut; - - // UTXO entries — read input values before erasing for money supply - if (!tx.IsCoinBase()) - { - int64_t nTxValueIn = 0; - for (const CTxIn& txin : tx.vin) - { - CUtxoEntry utxo; - if (txdb.ReadUtxo(txin.prevout.hash, txin.prevout.n, utxo)) - nTxValueIn += utxo.nValue; - if (fAddressIndex && !utxo.scriptPubKey.empty() && utxo.nValue != 0) - { - int nAType; uint160 aHash; - if (GetAddressFromScript(utxo.scriptPubKey, nAType, aHash)) - { - txdb.EraseAddressUtxo(nAType, aHash, txin.prevout.hash, txin.prevout.n); - int64_t nABal = 0; - txdb.ReadAddressBalance(nAType, aHash, nABal); - nABal -= utxo.nValue; - txdb.WriteAddressBalance(nAType, aHash, nABal); - } - } - txdb.EraseUtxo(txin.prevout.hash, txin.prevout.n); - } - nBlockValueIn += nTxValueIn; - if (!tx.IsCoinStake()) - nFees += nTxValueIn - nTxValueOut; - } - for (unsigned int k = 0; k < tx.vout.size(); k++) - { - if (!tx.vout[k].IsEmpty()) - { - CUtxoEntry utxo; - utxo.nValue = tx.vout[k].nValue; - utxo.nHeight = pindexNew->nHeight; - utxo.scriptPubKey = tx.vout[k].scriptPubKey; - utxo.fCoinBase = tx.IsCoinBase(); - utxo.fCoinStake = tx.IsCoinStake(); - utxo.nTxTime = tx.nTime; - txdb.WriteUtxo(hashTx, k, utxo); - if (fAddressIndex && !tx.vout[k].scriptPubKey.empty() && tx.vout[k].nValue != 0) - { - int nAType; uint160 aHash; - if (GetAddressFromScript(tx.vout[k].scriptPubKey, nAType, aHash)) - { - txdb.WriteAddressUtxo(nAType, aHash, hashTx, k, - tx.vout[k].nValue, pindexNew->nHeight, tx.vout[k].scriptPubKey); - int64_t nABal = 0; - txdb.ReadAddressBalance(nAType, aHash, nABal); - nABal += tx.vout[k].nValue; - txdb.WriteAddressBalance(nAType, aHash, nABal); - txdb.WriteAddressTxId(nAType, aHash, pindexNew->nHeight, (int)nTxIdx, hashTx); - } - } - } - } - } - - // Money supply tracking — matches ConnectBlock formula - pindexNew->nMint = nBlockValueOut - nBlockValueIn + nFees; - pindexNew->nMoneySupply = (pindexNew->pprev ? pindexNew->pprev->nMoneySupply : 0) + nBlockValueOut - nBlockValueIn; - - // Write block index to batch - txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); - - // Update best chain - if (pindexNew->nChainTrust > nBestChainTrust) - { - hashBestChain = hash; - pindexBest = pindexNew; - pblockindexFBBHLast = nullptr; - nBestHeight = pindexNew->nHeight; - nBestChainTrust = pindexNew->nChainTrust; - nTimeBestReceived = GetTime(); - } - - // Set genesis block - if (pindexGenesisBlock == nullptr && pindexNew->nHeight == 0) - pindexGenesisBlock = pindexNew; - - nLoaded++; - nPos += 4 + nSize; - - // Batch commit every 200K blocks for LevelDB efficiency - if (nLoaded % 200000 == 0) - { - txdb.WriteHashBestChain(hashBestChain); - txdb.TxnCommit(); - txdb.TxnBegin(); - } - - // Report progress every 5000 blocks to keep GUI responsive. - // AppInit2 runs on the GUI thread, so uiInterface.InitMessage - // triggers processEvents() which prevents the window from freezing. - if (nLoaded % 5000 == 0) - { - int pct = (nFileSize > 0) ? (int)((int64_t)nPos * 100 / nFileSize) : 0; - printf("FastImport: %d blocks indexed (%d%%)\n", nLoaded, pct); - uiInterface.InitMessage(strprintf(_("Importing blocks... %d indexed (%d%%)"), nLoaded, pct)); - } - } - - // Final commit - if (pindexBest) - { - if (fAddressIndex) - UpdateAddressIndexSyncState(txdb, pindexBest); - txdb.WriteHashBestChain(hashBestChain); - - // Write sync checkpoint - Checkpoints::WriteSyncCheckpoint(hashBestChain); - } - txdb.TxnCommit(); - } - - nTransactionsUpdated++; - printf("FastImportBlockFile: indexed %d blocks in %" PRId64 "ms\n", nLoaded, GetTimeMillis() - nStart); - return nLoaded > 0; -} - string GetWarnings(string strFor) { string strStatusBar; string strRPC; - if (GetBoolArg("-testsafemode")) - strRPC = "test"; - - // Misc warnings like out of disk space and clock is wrong - if (strMiscWarning != "") - strStatusBar = strMiscWarning; - // triangles: if detected invalid checkpoint enter safe mode if (Checkpoints::hashInvalidCheckpoint != 0) strStatusBar = strRPC = _("WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or notify developers."); diff --git a/src/main.h b/src/main.h index 39562ca..274ba1f 100644 --- a/src/main.h +++ b/src/main.h @@ -129,7 +129,6 @@ CBlockIndex* FindBlockByHeight(int nHeight); bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); bool LoadExternalBlockFile(FILE* fileIn); -bool FastImportBlockFile(); bool CheckProofOfWork(uint256 hash, unsigned int nBits); unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake);