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.
501class NotificationsHandlerImpl : public Handler502{503public:504explicit NotificationsHandlerImpl(ValidationSignals& signals, std::shared_ptr<Chain::Notifications> notifications)505: m_signals{signals}, m_proxy{std::make_shared<NotificationsProxy>(std::move(notifications))}506{507m_signals.RegisterSharedValidationInterface(m_proxy);508}509~NotificationsHandlerImpl() override { disconnect(); }510void disconnect() override511{512if (m_proxy) {513m_signals.UnregisterSharedValidationInterface(m_proxy);514m_proxy.reset();515}516}517ValidationSignals& m_signals;518std::shared_ptr<NotificationsProxy> m_proxy;519};521class RpcHandlerImpl : public Handler522{523public:524explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)525{526m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {527if (!m_wrapped_command) return false;528try {529return m_wrapped_command->actor(request, result, last_handler);530} catch (const UniValue& e) {531// If this is not the last handler and a wallet not found532// exception was thrown, return false so the next handler can533// try to handle the request. Otherwise, reraise the exception.534if (!last_handler) {535const UniValue& code = e["code"];536if (code.isNum() && code.getInt<int>() == RPC_WALLET_NOT_FOUND) {537return false;538}539}540throw;541}542};543::tableRPC.appendCommand(m_command.name, &m_command);544}546void disconnect() final547{548if (m_wrapped_command) {549m_wrapped_command = nullptr;550::tableRPC.removeCommand(m_command.name, &m_command);551}552}554~RpcHandlerImpl() override { disconnect(); }556CRPCCommand m_command;557const CRPCCommand* m_wrapped_command;558};560class ChainImpl : public Chain561{562public:563explicit ChainImpl(NodeContext& node) : m_node(node) {}564std::optional<int> getHeight() override565{566const int height{WITH_LOCK(::cs_main, return chainman().ActiveChain().Height())};567return height >= 0 ? std::optional{height} : std::nullopt;568}569uint256 getBlockHash(int height) override570{571LOCK(::cs_main);572return Assert(chainman().ActiveChain()[height])->GetBlockHash();573}574bool haveBlockOnDisk(int height) override575{576LOCK(::cs_main);577const CBlockIndex* block{chainman().ActiveChain()[height]};578return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;579}580std::optional<int> findLocatorFork(const CBlockLocator& locator) override581{582LOCK(::cs_main);583if (const CBlockIndex* fork = chainman().ActiveChainstate().FindForkInGlobalIndex(locator)) {584return fork->nHeight;585}586return std::nullopt;587}588bool hasBlockFilterIndex(BlockFilterType filter_type) override589{590return GetBlockFilterIndex(filter_type) != nullptr;591}592std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override593{594const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};595if (!block_filter_index) return std::nullopt;597BlockFilter filter;598const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};599if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;600return filter.GetFilter().MatchAny(filter_set);601}602bool findBlock(const uint256& hash, const FoundBlock& block) override603{604WAIT_LOCK(cs_main, lock);605return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain(), chainman().m_blockman);606}607bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override608{609WAIT_LOCK(cs_main, lock);610const CChain& active = chainman().ActiveChain();611return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active, chainman().m_blockman);612}613bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override614{615WAIT_LOCK(cs_main, lock);616const CChain& active = chainman().ActiveChain();617if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {618if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {619return FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman);620}621}622return FillBlock(nullptr, ancestor_out, lock, active, chainman().m_blockman);623}624bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override625{626WAIT_LOCK(cs_main, lock);627const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);628const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);629if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;630return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain(), chainman().m_blockman);631}632bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override633{634WAIT_LOCK(cs_main, lock);635const CChain& active = chainman().ActiveChain();636const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);637const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);638const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;639// Using & instead of && below to avoid short circuiting and leaving640// output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical641// compiler warnings.642return int{FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman)} &643int{FillBlock(block1, block1_out, lock, active, chainman().m_blockman)} &644int{FillBlock(block2, block2_out, lock, active, chainman().m_blockman)};645}646void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }647double guessVerificationProgress(const uint256& block_hash) override648{649LOCK(chainman().GetMutex());650return chainman().GuessVerificationProgress(chainman().m_blockman.LookupBlockIndex(block_hash));651}652bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override653{654// hasBlocks returns true if all ancestors of block_hash in specified655// range have block data (are not pruned), false if any ancestors in656// specified range are missing data.657//658// For simplicity and robustness, min_height and max_height are only659// used to limit the range, and passing min_height that's too low or660// max_height that's too high will not crash or change the result.661LOCK(::cs_main);662if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {663if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);664for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {665// Check pprev to not segfault if min_height is too low666if (block->nHeight <= min_height || !block->pprev) return true;667}668}669return false;670}671RBFTransactionState isRBFOptIn(const CTransaction& tx) override672{673if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);674LOCK(m_node.mempool->cs);675return IsRBFOptIn(tx, *m_node.mempool);676}677bool isInMempool(const Txid& txid) override678{679if (!m_node.mempool) return false;680return m_node.mempool->exists(txid);681}682bool hasDescendantsInMempool(const Txid& txid) override683{684if (!m_node.mempool) return false;685return m_node.mempool->HasDescendants(txid);686}687bool broadcastTransaction(const CTransactionRef& tx,688const CAmount& max_tx_fee,689TxBroadcast broadcast_method,690std::string& err_string) override691{692const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, broadcast_method, /*wait_callback=*/false);693// Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.694// Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures695// that Chain clients do not need to know about.696return TransactionError::OK == err;697}698void getTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& cluster_count, size_t* ancestorsize, CAmount* ancestorfees) override699{700ancestors = cluster_count = 0;701if (!m_node.mempool) return;702m_node.mempool->GetTransactionAncestry(txid, ancestors, cluster_count, ancestorsize, ancestorfees);703}705std::map<COutPoint, CAmount> calculateIndividualBumpFees(const std::vector<COutPoint>& outpoints, const CFeeRate& target_feerate) override706{707if (!m_node.mempool) {708std::map<COutPoint, CAmount> bump_fees;709for (const auto& outpoint : outpoints) {710bump_fees.emplace(outpoint, 0);711}712return bump_fees;713}714return MiniMiner(*m_node.mempool, outpoints).CalculateBumpFees(target_feerate);715}717std::optional<CAmount> calculateCombinedBumpFee(const std::vector<COutPoint>& outpoints, const CFeeRate& target_feerate) override718{719if (!m_node.mempool) {720return 0;721}722return MiniMiner(*m_node.mempool, outpoints).CalculateTotalBumpFees(target_feerate);723}724void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override725{726const CTxMemPool::Limits default_limits{};728const CTxMemPool::Limits& limits{m_node.mempool ? m_node.mempool->m_opts.limits : default_limits};730limit_ancestor_count = limits.ancestor_count;731limit_descendant_count = limits.descendant_count;732}733util::Result<void> checkChainLimits(const CTransactionRef& tx) override734{735if (!m_node.mempool) return {};736if (!m_node.mempool->CheckPolicyLimits(tx)) {737return util::Error{Untranslated("too many unconfirmed transactions in cluster")};738}739return {};740}741util::Expected<FeeRateEstimation, FeeRateEstimationError> getFeeRateEstimate(int num_blocks, bool conservative) const override742{743if (!m_node.fee_estimator_man) return EstimationError(FeeRateEstimatorType::AUTO, /*returned_target=*/0, /*error=*/{});744return m_node.fee_estimator_man->GetFeeRateEstimate(num_blocks, conservative);745}746unsigned int maximumFeeEstimationTargetBlocks() const override747{748if (!m_node.fee_estimator_man) return 0;749return m_node.fee_estimator_man->MaximumTarget();750}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.