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.
1// Copyright (c) 2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <bitcoin-build-config.h> // IWYU pragma: keep8#include <interfaces/mining.h>9#include <rpc/register.h> // IWYU pragma: associated11#include <addresstype.h>12#include <arith_uint256.h>13#include <chain.h>14#include <chainparams.h>15#include <chainparamsbase.h>16#include <consensus/amount.h>17#include <consensus/consensus.h>18#include <consensus/merkle.h>19#include <consensus/params.h>20#include <consensus/validation.h>21#include <core_io.h>22#include <crypto/hex_base.h>23#include <interfaces/types.h>24#include <key_io.h>25#include <net.h>26#include <netbase.h>27#include <node/blockstorage.h>28#include <node/context.h>29#include <node/miner.h>30#include <node/mining_args.h>31#include <node/mining_types.h>32#include <node/warnings.h>33#include <policy/feerate.h>34#include <policy/policy.h>35#include <pow.h>36#include <primitives/block.h>37#include <primitives/transaction.h>38#include <rpc/blockchain.h>39#include <rpc/mining.h>40#include <rpc/protocol.h>41#include <rpc/request.h>42#include <rpc/server.h>43#include <rpc/server_util.h>44#include <rpc/util.h>45#include <script/descriptor.h>46#include <script/script.h>47#include <script/signingprovider.h>48#include <serialize.h>49#include <streams.h>50#include <sync.h>51#include <tinyformat.h>52#include <txmempool.h>53#include <uint256.h>54#include <univalue.h>55#include <util/chaintype.h>56#include <util/check.h>57#include <util/signalinterrupt.h>58#include <util/strencodings.h>59#include <util/string.h>60#include <util/time.h>61#include <validation.h>62#include <validationinterface.h>63#include <versionbits.h>65#include <algorithm>66#include <cstddef>67#include <cstdint>68#include <functional>69#include <limits>70#include <map>71#include <memory>72#include <optional>73#include <set>74#include <span>75#include <string>76#include <string_view>77#include <utility>78#include <vector>80using interfaces::BlockRef;81using interfaces::BlockTemplate;82using interfaces::Mining;83using node::BlockAssembler;84using node::GetMinimumTime;85using node::NodeContext;86using node::RegenerateCommitments;87using node::UpdateTime;88using util::ToString;90/**91* Return average network hashes per second based on the last 'lookup' blocks,92* or from the last difficulty change if 'lookup' is -1.93* If 'height' is -1, compute the estimate from current chain tip.94* If 'height' is a valid block height, compute the estimate at the time when a given block was found.95*/96static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_chain) {97if (lookup < -1 || lookup == 0) {98throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks. Must be a positive number or -1.");99}101if (height < -1 || height > active_chain.Height()) {102throw JSONRPCError(RPC_INVALID_PARAMETER, "Block does not exist at specified height");103}105const CBlockIndex* pb = active_chain.Tip();107if (height >= 0) {108pb = active_chain[height];109}111if (pb == nullptr || !pb->nHeight)112return 0;114// If lookup is -1, then use blocks since last difficulty change.115if (lookup == -1)116lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1;118// If lookup is larger than chain, then set it to chain length.119if (lookup > pb->nHeight)120lookup = pb->nHeight;122const CBlockIndex* pb0 = pb;123int64_t minTime = pb0->GetBlockTime();124int64_t maxTime = minTime;125for (int i = 0; i < lookup; i++) {126pb0 = pb0->pprev;127int64_t time = pb0->GetBlockTime();128minTime = std::min(time, minTime);129maxTime = std::max(time, maxTime);130}132// In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.133if (minTime == maxTime)134return 0;136arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;137int64_t timeDiff = maxTime - minTime;139return workDiff.getdouble() / timeDiff;140}142static RPCMethod getnetworkhashps()143{144return RPCMethod{145"getnetworkhashps",146"Returns the estimated network hashes per second based on the last n blocks.\n"147"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"148"Pass in [height] to estimate the network speed at the time when a certain block was found.\n",149{150{"nblocks", RPCArg::Type::NUM, RPCArg::Default{120}, "The number of previous blocks to calculate estimate from, or -1 for blocks since last difficulty change."},151{"height", RPCArg::Type::NUM, RPCArg::Default{-1}, "To estimate at the time of the given height."},152},153RPCResult{154RPCResult::Type::NUM, "", "Hashes per second estimated"},155RPCExamples{156HelpExampleCli("getnetworkhashps", "")157+ HelpExampleRpc("getnetworkhashps", "")158},159[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue160{161ChainstateManager& chainman = EnsureAnyChainman(request.context);162LOCK(cs_main);163return GetNetworkHashPS(self.Arg<int>("nblocks"), self.Arg<int>("height"), chainman.ActiveChain());164},165};166}168static bool GenerateBlock(ChainstateManager& chainman, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)169{170block_out.reset();171block.hashMerkleRoot = BlockMerkleRoot(block);173while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !chainman.m_interrupt) {174++block.nNonce;175--max_tries;176}177if (max_tries == 0 || chainman.m_interrupt) {178return false;179}180if (block.nNonce == std::numeric_limits<uint32_t>::max()) {181return true;182}184block_out = std::make_shared<const CBlock>(std::move(block));186if (!process_new_block) return true;188if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {189throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");190}192return true;193}195static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_output_script, int nGenerate, uint64_t nMaxTries)196{197UniValue blockHashes(UniValue::VARR);198while (nGenerate > 0 && !chainman.m_interrupt) {199std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock({ .coinbase_output_script = coinbase_output_script }, /*cooldown=*/false));200CHECK_NONFATAL(block_template);202std::shared_ptr<const CBlock> block_out;203if (!GenerateBlock(chainman, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {204break;205}207if (block_out) {208--nGenerate;209blockHashes.push_back(block_out->GetHash().GetHex());210}211}212return blockHashes;213}215static bool getScriptFromDescriptor(std::string_view descriptor, CScript& script, std::string& error)216{217FlatSigningProvider key_provider;218const auto descs = Parse(descriptor, key_provider, error, /* require_checksum = */ false);219if (descs.empty()) return false;220if (descs.size() > 1) {221throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptor not accepted");222}223const auto& desc = descs.at(0);224if (desc->IsRange()) {225throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");226}228FlatSigningProvider provider;229std::vector<CScript> scripts;230if (!desc->Expand(0, key_provider, scripts, provider)) {231throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");232}234// Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1235CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);237if (scripts.size() == 1) {238script = scripts.at(0);239} else if (scripts.size() == 4) {240// For uncompressed keys, take the 3rd script, since it is p2wpkh241script = scripts.at(2);242} else {243// Else take the 2nd script, since it is p2pkh244script = scripts.at(1);245}247return true;248}250static RPCMethod generatetodescriptor()