Inside Bitcoin
Opening the selected file…
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.
251}253bool BlockAssembler::TestChunkBlockLimits(int64_t chunk_weight, int64_t chunk_sigops_cost) const254{255// block_max_weight has been flattened before block assembly limit checks.256Assert(m_options.block_max_weight);257if (nBlockWeight + chunk_weight >= m_options.block_max_weight) {258return false;259}260if (nBlockSigOpsCost + chunk_sigops_cost >= MAX_BLOCK_SIGOPS_COST) {261return false;262}263return true;264}266// Perform transaction-level checks before adding to block:267// - transaction finality (locktime)268bool BlockAssembler::TestChunkTransactions(const std::vector<CTxMemPoolEntryRef>& txs) const269{270for (const auto tx : txs) {271if (!IsFinalTx(tx.get().GetTx(), nHeight, m_lock_time_cutoff)) {272return false;273}274}275return true;276}278void BlockAssembler::AddToBlock(const CTxMemPoolEntry& entry)279{280pblocktemplate->block.vtx.emplace_back(entry.GetSharedTx());281pblocktemplate->vTxFees.push_back(entry.GetFee());282pblocktemplate->vTxSigOpsCost.push_back(entry.GetSigOpCost());283nBlockWeight += entry.GetTxWeight();284++nBlockTx;285nBlockSigOpsCost += entry.GetSigOpCost();286nFees += entry.GetFee();288if (*m_options.print_modified_fee) {289LogInfo("fee rate %s txid %s\n",290CFeeRate(entry.GetModifiedFee(), entry.GetTxSize()).ToString(),291entry.GetTx().GetHash().ToString());292}293}295void BlockAssembler::addChunks()296{297// Limit the number of attempts to add transactions to the block when it is298// close to full; this is just a simple heuristic to finish quickly if the299// mempool has a lot of entries.300const int64_t MAX_CONSECUTIVE_FAILURES = 1000;301constexpr int32_t BLOCK_FULL_ENOUGH_WEIGHT_DELTA = 4000;302int64_t nConsecutiveFailed = 0;304std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> selected_transactions;305selected_transactions.reserve(MAX_CLUSTER_COUNT_LIMIT);306FeePerWeight chunk_feerate;308// This fills selected_transactions309chunk_feerate = m_mempool->GetBlockBuilderChunk(selected_transactions);310FeePerVSize chunk_feerate_vsize = ToFeePerVSize(chunk_feerate);312while (selected_transactions.size() > 0) {313// Check to see if min fee rate is still respected.314if (ByRatio{chunk_feerate_vsize} < ByRatio{m_options.block_min_fee_rate->GetFeePerVSize()}) {315// Everything else we might consider has a lower feerate316return;317}319int64_t chunk_sig_ops = 0;320int64_t chunk_weight = 0;321for (const auto& tx : selected_transactions) {322chunk_sig_ops += tx.get().GetSigOpCost();323chunk_weight += tx.get().GetTxWeight();324}326// Check to see if this chunk will fit.327if (!TestChunkBlockLimits(chunk_weight, chunk_sig_ops) || !TestChunkTransactions(selected_transactions)) {328// This chunk won't fit, so we skip it and will try the next best one.329m_mempool->SkipBuilderChunk();330++nConsecutiveFailed;332// block_max_weight has been flattened before block assembly limit checks.333Assert(m_options.block_max_weight);334if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight +335BLOCK_FULL_ENOUGH_WEIGHT_DELTA > *m_options.block_max_weight) {336// Give up if we're close to full and haven't succeeded in a while337return;338}339} else {340m_mempool->IncludeBuilderChunk();342// This chunk will fit, so add it to the block.343nConsecutiveFailed = 0;344for (const auto& tx : selected_transactions) {345AddToBlock(tx);346}347pblocktemplate->m_package_feerates.emplace_back(chunk_feerate_vsize);348}350selected_transactions.clear();351chunk_feerate = m_mempool->GetBlockBuilderChunk(selected_transactions);352chunk_feerate_vsize = ToFeePerVSize(chunk_feerate);353}354}356void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce)357{358if (block.vtx.size() == 0) {359block.vtx.emplace_back(coinbase);360} else {361block.vtx[0] = coinbase;362}363block.nVersion = version;364block.nTime = timestamp;365block.nNonce = nonce;366block.hashMerkleRoot = BlockMerkleRoot(block);368// Reset cached checks369block.m_checked_witness_commitment = false;370block.m_checked_merkle_root = false;371block.fChecked = false;372}374namespace {375class SubmitBlockStateCatcher final : public CValidationInterface376{377public:378uint256 m_hash;379bool m_found{false};380BlockValidationState m_state;382explicit SubmitBlockStateCatcher(const uint256& hash) : m_hash{hash} {}384protected:385void BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& state) override386{387if (block->GetHash() != m_hash) return;388// ProcessNewBlock emits BlockChecked synchronously while holding cs_main,389// so SubmitBlock can read these fields after ProcessNewBlock returns390// without extra synchronization.391m_found = true;392m_state = state;393}394};395} // namespace397bool SubmitBlock(ChainstateManager& chainman, const std::shared_ptr<const CBlock>& block, std::string& reason, std::string& debug)398{399reason.clear();400debug.clear();402// This follows the submitblock RPC's validation-state capture pattern, but403// is intentionally kept separate from the RPC implementation. The RPC entry404// point decodes hex, formats BIP22/JSONRPC results, and calls405// UpdateUncommittedBlockStructures() for legacy witness handling. IPC406// callers submit already-formed blocks and need bool + reason/debug407// results.408auto sc = std::make_shared<SubmitBlockStateCatcher>(block->GetHash());409CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);410bool new_block;411bool accepted = chainman.ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);412// No queue drain is needed. The BlockChecked notification used above is413// emitted synchronously by ProcessNewBlock, unlike most validation signals.414CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);416if (!new_block && accepted) {417reason = "duplicate";418} else if (!accepted && (!sc->m_found || sc->m_state.IsValid())) {419// ProcessNewBlock can fail without a validation result, for example420// from an activation or system error. It can also fail after a valid421// BlockChecked result. In these cases the validation result is422// inconclusive.423reason = "inconclusive";424} else if (!sc->m_found) {425// The block was accepted but not connected, for example if it does not426// have more work than the current tip.427reason = "inconclusive";428} else if (!sc->m_state.IsValid()) {429reason = sc->m_state.GetRejectReason();430debug = sc->m_state.GetDebugMessage();431}432const bool result{accepted && new_block && reason.empty()};433CHECK_NONFATAL(result == reason.empty());434return result;435}437void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait)438{439LOCK(kernel_notifications.m_tip_block_mutex);440interrupt_wait = true;441kernel_notifications.m_tip_block_cv.notify_all();442}444std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,445KernelNotifications& kernel_notifications,446CTxMemPool* mempool,447const std::unique_ptr<CBlockTemplate>& block_template,448const BlockWaitOptions& wait_options,449const BlockCreateOptions& create_options,450bool& interrupt_wait)451{452// Delay calculating the current template fees, just in case a new block453// comes in before the next tick.454CAmount current_fees = -1;456// Alternate waiting for a new tip and checking if fees have risen.457// The latter check is expensive so we only run it once per second.458auto now{NodeClock::now()};459const auto deadline = now + wait_options.timeout;460const MillisecondsDouble tick{1000};461const bool allow_min_difficulty{chainman.GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};463do {464bool tip_changed{false};465{466WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);467// Note that wait_until() checks the predicate before waiting468kernel_notifications.m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {469AssertLockHeld(kernel_notifications.m_tip_block_mutex);470const auto tip_block{kernel_notifications.TipBlock()};471// We assume tip_block is set, because this is an instance472// method on BlockTemplate and no template could have been473// generated before a tip exists.474tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;475return tip_changed || chainman.m_interrupt || interrupt_wait;476});477if (interrupt_wait) {478interrupt_wait = false;479return nullptr;480}481}483if (chainman.m_interrupt) return nullptr;484// At this point the tip changed, a full tick went by or we reached485// the deadline.487// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.488LOCK(::cs_main);490// On test networks return a minimum difficulty block after 20 minutes491if (!tip_changed && allow_min_difficulty) {492const NodeClock::time_point tip_time{std::chrono::seconds{chainman.ActiveChain().Tip()->GetBlockTime()}};493if (now > tip_time + 20min) {494tip_changed = true;495}496}498/**499* We determine if fees increased compared to the previous template by generating500* a fresh template. There may be more efficient ways to determine how much