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) 2009-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 <rest.h>8#include <blockfilter.h>9#include <chain.h>10#include <coins.h>11#include <consensus/params.h>12#include <core_io.h>13#include <crypto/hex_base.h>14#include <flatfile.h>15#include <httpserver.h>16#include <index/blockfilterindex.h>17#include <index/txindex.h>18#include <node/blockstorage.h>19#include <node/context.h>20#include <node/transaction.h>21#include <primitives/block.h>22#include <primitives/transaction.h>23#include <rpc/blockchain.h>24#include <rpc/mempool.h>25#include <rpc/protocol.h>26#include <rpc/request.h>27#include <rpc/server.h>28#include <rpc/util.h>29#include <serialize.h>30#include <streams.h>31#include <sync.h>32#include <tinyformat.h>33#include <txmempool.h>34#include <uint256.h>35#include <undo.h>36#include <univalue.h>37#include <util/any.h>38#include <util/check.h>39#include <util/overflow.h>40#include <util/strencodings.h>41#include <util/string.h>42#include <validation.h>44#include <any>45#include <cstdint>46#include <cstring>47#include <ios>48#include <memory>49#include <optional>50#include <span>51#include <stdexcept>52#include <string_view>53#include <utility>54#include <vector>56using node::GetTransaction;57using node::NodeContext;58using util::SplitString;60static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once61static constexpr unsigned int MAX_REST_HEADERS_RESULTS = 2000;63// Cache-Control values for REST responses.64/** Response bytes never change. One-day TTL limits staleness across software upgrades. */65static constexpr const char* REST_CACHE_IMMUTABLE = "public, immutable, max-age=86400";66/** Mutable, node-local, or error response; must not be cached. */67static constexpr const char* REST_CACHE_NO_STORE = "no-store";69static const struct {70RESTResponseFormat rf;71const char* name;72} rf_names[] = {73{RESTResponseFormat::UNDEF, ""},74{RESTResponseFormat::BINARY, "bin"},75{RESTResponseFormat::HEX, "hex"},76{RESTResponseFormat::JSON, "json"},77};79struct CCoin {80uint32_t nHeight;81CTxOut out;83CCoin() : nHeight(0) {}84explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}86SERIALIZE_METHODS(CCoin, obj)87{88uint32_t nTxVerDummy = 0;89READWRITE(nTxVerDummy, obj.nHeight, obj.out);90}91};93static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)94{95req->WriteHeader("Cache-Control", REST_CACHE_NO_STORE);96req->WriteHeader("Content-Type", "text/plain");97req->WriteReply(status, message + "\r\n");98return false;99}101/**102* Get the node context.103*104* @param[in] req The HTTP request, whose status code will be set if node105* context is not found.106* @returns Pointer to the node context or nullptr if not found.107*/108static NodeContext* GetNodeContext(const std::any& context, HTTPRequest* req)109{110auto node_context = util::AnyPtr<NodeContext>(context);111if (!node_context) {112RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, STR_INTERNAL_BUG("Node context not found!"));113return nullptr;114}115return node_context;116}118/**119* Get the node context mempool.120*121* @param[in] req The HTTP request, whose status code will be set if node122* context mempool is not found.123* @returns Pointer to the mempool or nullptr if no mempool found.124*/125static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req)126{127auto node_context = util::AnyPtr<NodeContext>(context);128if (!node_context || !node_context->mempool) {129RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found");130return nullptr;131}132return node_context->mempool.get();133}135/**136* Get the node context chainstatemanager.137*138* @param[in] req The HTTP request, whose status code will be set if node139* context chainstatemanager is not found.140* @returns Pointer to the chainstatemanager or nullptr if none found.141*/142static ChainstateManager* GetChainman(const std::any& context, HTTPRequest* req)143{144auto node_context = util::AnyPtr<NodeContext>(context);145if (!node_context || !node_context->chainman) {146RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, STR_INTERNAL_BUG("Chainman disabled or instance not found!"));147return nullptr;148}149return node_context->chainman.get();150}152RESTResponseFormat ParseDataFormat(std::string& param, const std::string& strReq)153{154// Remove query string (if any, separated with '?') as it should not interfere with155// parsing param and data format156param = strReq.substr(0, strReq.rfind('?'));157const std::string::size_type pos_format{param.rfind('.')};159// No format string is found160if (pos_format == std::string::npos) {161return RESTResponseFormat::UNDEF;162}164// Match format string to available formats165const std::string suffix(param, pos_format + 1);166for (const auto& rf_name : rf_names) {167if (suffix == rf_name.name) {168param.erase(pos_format);169return rf_name.rf;170}171}173// If no suffix is found, return RESTResponseFormat::UNDEF and original string without query string174return RESTResponseFormat::UNDEF;175}177static std::string AvailableDataFormatsString()178{179std::string formats;180for (const auto& rf_name : rf_names) {181if (strlen(rf_name.name) > 0) {182formats.append(".");183formats.append(rf_name.name);184formats.append(", ");185}186}188if (formats.length() > 0)189return formats.substr(0, formats.length() - 2);191return formats;192}194static bool CheckWarmup(HTTPRequest* req)195{196std::string statusmessage;197if (RPCIsInWarmup(&statusmessage))198return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);199return true;200}202static bool rest_headers(const std::any& context,203HTTPRequest* req,204const std::string& uri_part)205{206if (!CheckWarmup(req))207return false;208std::string param;209const RESTResponseFormat rf = ParseDataFormat(param, uri_part);210std::vector<std::string> path = SplitString(param, '/');212std::string raw_count;213std::string hashStr;214if (path.size() == 2) {215// deprecated path: /rest/headers/<count>/<hash>216hashStr = path[1];217raw_count = path[0];218} else if (path.size() == 1) {219// new path with query parameter: /rest/headers/<hash>?count=<count>220hashStr = path[0];221try {222raw_count = req->GetQueryParameter("count").value_or("5");223} catch (const std::runtime_error& e) {224return RESTERR(req, HTTP_BAD_REQUEST, e.what());225}226} else {227return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");228}230const auto parsed_count{ToIntegral<size_t>(raw_count)};231if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) {232return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, raw_count));233}235auto hash{uint256::FromHex(hashStr)};236if (!hash) {237return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);238}240const CBlockIndex* tip = nullptr;241std::vector<const CBlockIndex*> headers;242headers.reserve(*parsed_count);243ChainstateManager* maybe_chainman = GetChainman(context, req);244if (!maybe_chainman) return false;245ChainstateManager& chainman = *maybe_chainman;246{247LOCK(cs_main);248CChain& active_chain = chainman.ActiveChain();249tip = active_chain.Tip();250const CBlockIndex* pindex{chainman.m_blockman.LookupBlockIndex(*hash)};
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.