Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
2501pindex->nHeight, block_hash.ToString());2502}2503m_last_script_check_reason_logged = script_check_reason;2504}2506CBlockUndo blockundo;2508// Precomputed transaction data pointers must not be invalidated2509// until after `control` has run the script checks (potentially2510// in multiple threads). Preallocate the vector size so a new allocation2511// doesn't invalidate pointers into the vector, and keep txsdata in scope2512// for as long as `control`.2513std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());2514std::optional<CCheckQueueControl<CScriptCheck>> control;2515if (auto& queue = m_chainman.GetCheckQueue(); queue.HasThreads() && fScriptChecks) control.emplace(queue);2517std::vector<int> prevheights;2518CAmount nFees = 0;2519int nInputs = 0;2520int64_t nSigOpsCost = 0;2521blockundo.vtxundo.reserve(block.vtx.size() - 1);2522for (unsigned int i = 0; i < block.vtx.size(); i++)2523{2524if (!state.IsValid()) break;2525const CTransaction &tx = *(block.vtx[i]);2527nInputs += tx.vin.size();2529if (!tx.IsCoinBase())2530{2531CAmount txfee = 0;2532TxValidationState tx_state;2533if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) {2534// Any transaction validation failure in ConnectBlock is a block consensus failure2535state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,2536tx_state.GetRejectReason(),2537tx_state.GetDebugMessage() + " in transaction " + tx.GetHash().ToString());2538break;2539}2540nFees += txfee;2541if (!MoneyRange(nFees)) {2542state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange",2543"accumulated fee in the block out of range");2544break;2545}2547// Check that transaction is BIP68 final2548// BIP68 lock checks (as opposed to nLockTime checks) must2549// be in ConnectBlock because they require the UTXO set2550prevheights.resize(tx.vin.size());2551for (size_t j = 0; j < tx.vin.size(); j++) {2552prevheights[j] = view.AccessCoin(tx.vin[j].prevout).nHeight;2553}2555if (!SequenceLocks(tx, nLockTimeFlags, prevheights, *pindex)) {2556state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-nonfinal",2557"contains a non-BIP68-final transaction " + tx.GetHash().ToString());2558break;2559}2560}2562// GetTransactionSigOpCost counts 3 types of sigops:2563// * legacy (always)2564// * p2sh (when P2SH enabled in flags and excludes coinbase)2565// * witness (when witness enabled in flags and excludes coinbase)2566nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);2567if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST) {2568state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sigops", "too many sigops");2569break;2570}2572if (!tx.IsCoinBase() && fScriptChecks)2573{2574bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */2575bool tx_ok;2576TxValidationState tx_state;2577// If CheckInputScripts is called with a pointer to a checks vector, the resulting checks are appended to it. In that case2578// they need to be added to control which runs them asynchronously. Otherwise, CheckInputScripts runs the checks before returning.2579if (control) {2580std::vector<CScriptCheck> vChecks;2581tx_ok = CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, &vChecks);2582if (tx_ok) control->Add(std::move(vChecks));2583} else {2584tx_ok = CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache);2585}2586if (!tx_ok) {2587// Any transaction validation failure in ConnectBlock is a block consensus failure2588state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,2589tx_state.GetRejectReason(), tx_state.GetDebugMessage());2590break;2591}2592}2594CTxUndo undoDummy;2595if (i > 0) {2596blockundo.vtxundo.emplace_back();2597}2598UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);2599}2600const auto time_3{SteadyClock::now()};2601m_chainman.time_connect += time_3 - time_2;2602LogDebug(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(),2603Ticks<MillisecondsDouble>(time_3 - time_2), Ticks<MillisecondsDouble>(time_3 - time_2) / block.vtx.size(),2604nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_3 - time_2) / (nInputs - 1),2605Ticks<SecondsDouble>(m_chainman.time_connect),2606Ticks<MillisecondsDouble>(m_chainman.time_connect) / m_chainman.num_blocks_total);2608CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, params.GetConsensus());2609if (block.vtx[0]->GetValueOut() > blockReward && state.IsValid()) {2610state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount",2611strprintf("coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0]->GetValueOut(), blockReward));2612}2613if (control) {2614auto parallel_result = control->Complete();2615if (parallel_result.has_value() && state.IsValid()) {2616state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, strprintf("block-script-verify-flag-failed (%s)", ScriptErrorString(parallel_result->first)), parallel_result->second);2617}2618}2619if (!state.IsValid()) {2620LogInfo("Block validation error: %s", state.ToString());2621return false;2622}2623const auto time_4{SteadyClock::now()};2624m_chainman.time_verify += time_4 - time_2;2625LogDebug(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1,2626Ticks<MillisecondsDouble>(time_4 - time_2),2627nInputs <= 1 ? 0 : Ticks<MillisecondsDouble>(time_4 - time_2) / (nInputs - 1),2628Ticks<SecondsDouble>(m_chainman.time_verify),2629Ticks<MillisecondsDouble>(m_chainman.time_verify) / m_chainman.num_blocks_total);2631if (fJustCheck) {2632return true;2633}2635if (!m_blockman.WriteBlockUndo(blockundo, state, *pindex)) {2636return false;2637}2639const auto time_5{SteadyClock::now()};2640m_chainman.time_undo += time_5 - time_4;2641LogDebug(BCLog::BENCH, " - Write undo data: %.2fms [%.2fs (%.2fms/blk)]\n",2642Ticks<MillisecondsDouble>(time_5 - time_4),2643Ticks<SecondsDouble>(m_chainman.time_undo),2644Ticks<MillisecondsDouble>(m_chainman.time_undo) / m_chainman.num_blocks_total);2646if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {2647pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);2648m_blockman.m_dirty_blockindex.insert(pindex);2649}2651// add this block to the view's block chain2652view.SetBestBlock(pindex->GetBlockHash());2654const auto time_6{SteadyClock::now()};2655m_chainman.time_index += time_6 - time_5;2656LogDebug(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n",2657Ticks<MillisecondsDouble>(time_6 - time_5),2658Ticks<SecondsDouble>(m_chainman.time_index),2659Ticks<MillisecondsDouble>(m_chainman.time_index) / m_chainman.num_blocks_total);2661TRACEPOINT(validation, block_connected,2662block_hash.data(),2663pindex->nHeight,2664block.vtx.size(),2665nInputs,2666nSigOpsCost,2667Ticks<std::chrono::nanoseconds>(time_5 - time_start)2668);2670return true;2671}2673CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState()2674{2675AssertLockHeld(::cs_main);2676return this->GetCoinsCacheSizeState(2677m_coinstip_cache_size_bytes,2678m_mempool ? m_mempool->m_opts.max_size_bytes : 0);2679}2681CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState(2682size_t max_coins_cache_size_bytes,2683size_t max_mempool_size_bytes)2684{2685AssertLockHeld(::cs_main);2686const int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0;2687int64_t cacheSize = CoinsTip().DynamicMemoryUsage();2688int64_t nTotalSpace =2689max_coins_cache_size_bytes + std::max<int64_t>(int64_t(max_mempool_size_bytes) - nMempoolUsage, 0);2691if (cacheSize > nTotalSpace) {2692LogInfo("Cache size (%s) exceeds total space (%s)\n", cacheSize, nTotalSpace);2693return CoinsCacheSizeState::CRITICAL;2694} else if (cacheSize > LargeCoinsCacheThreshold(nTotalSpace)) {2695return CoinsCacheSizeState::LARGE;2696}2697return CoinsCacheSizeState::OK;2698}2700bool Chainstate::FlushStateToDisk(2701BlockValidationState &state,2702FlushStateMode mode,2703int nManualPruneHeight)2704{2705LOCK(cs_main);2706assert(this->CanFlushToDisk());2707std::set<int> setFilesToPrune;2708bool full_flush_completed = false;2710[[maybe_unused]] const size_t coins_count{CoinsTip().GetCacheSize()};2711[[maybe_unused]] const size_t coins_mem_usage{CoinsTip().DynamicMemoryUsage()};2713try {2714{2715bool fFlushForPrune = false;2717CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();2718if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && m_chainman.m_blockman.m_blockfiles_indexed) {2719// make sure we don't prune above any of the prune locks bestblocks2720// pruning is height-based2721int last_prune{m_chain.Height()}; // last height we can prune2722std::optional<std::string> limiting_lock; // prune lock that actually was the limiting factor, only used for logging2724for (const auto& prune_lock : m_blockman.m_prune_locks) {2725if (prune_lock.second.height_first == std::numeric_limits<int>::max()) continue;2726// Remove the buffer and one additional block here to get actual height that is outside of the buffer2727const int lock_height{prune_lock.second.height_first - PRUNE_LOCK_BUFFER - 1};2728last_prune = std::max(1, std::min(last_prune, lock_height));2729if (last_prune == lock_height) {2730limiting_lock = prune_lock.first;2731}2732}2734if (limiting_lock) {2735LogDebug(BCLog::PRUNE, "%s limited pruning to height %d\n", limiting_lock.value(), last_prune);2736}2738if (nManualPruneHeight > 0) {2739LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);2741m_blockman.FindFilesToPruneManual(2742setFilesToPrune,2743std::min(last_prune, nManualPruneHeight),2744*this);2745} else {2746LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);2748m_blockman.FindFilesToPrune(setFilesToPrune, last_prune, *this, m_chainman);2749m_blockman.m_check_for_pruning = false;2750}