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.
251continue;252}253obj.pushKV("id", stats.nodeid);254obj.pushKV("addr", stats.m_addr_name);255if (stats.addrBind.IsValid()) {256obj.pushKV("addrbind", stats.addrBind.ToStringAddrPort());257}258if (!(stats.addrLocal.empty())) {259obj.pushKV("addrlocal", stats.addrLocal);260}261obj.pushKV("network", GetNetworkName(stats.m_network));262if (stats.m_mapped_as != 0) {263obj.pushKV("mapped_as", stats.m_mapped_as);264}265ServiceFlags services{statestats.their_services};266obj.pushKV("services", strprintf("%016x", services));267obj.pushKV("servicesnames", GetServicesNames(services));268obj.pushKV("relaytxes", statestats.m_relay_txs);269obj.pushKV("last_inv_sequence", statestats.m_last_inv_seq);270obj.pushKV("inv_to_send", statestats.m_inv_to_send);271obj.pushKV("lastsend", TicksSinceEpoch<std::chrono::seconds>(stats.m_last_send));272obj.pushKV("lastrecv", TicksSinceEpoch<std::chrono::seconds>(stats.m_last_recv));273obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));274obj.pushKV("last_block", count_seconds(stats.m_last_block_time));275obj.pushKV("bytessent", stats.nSendBytes);276obj.pushKV("bytesrecv", stats.nRecvBytes);277obj.pushKV("conntime", TicksSinceEpoch<std::chrono::seconds>(stats.m_connected));278obj.pushKV("timeoffset", Ticks<std::chrono::seconds>(statestats.time_offset));279if (stats.m_last_ping_time > 0us) {280obj.pushKV("pingtime", Ticks<SecondsDouble>(stats.m_last_ping_time));281}282if (stats.m_min_ping_time < decltype(CNode::m_min_ping_time.load())::max()) {283obj.pushKV("minping", Ticks<SecondsDouble>(stats.m_min_ping_time));284}285if (statestats.m_ping_wait > 0s) {286obj.pushKV("pingwait", Ticks<SecondsDouble>(statestats.m_ping_wait));287}288obj.pushKV("version", stats.nVersion);289// Use the sanitized form of subver here, to avoid tricksy remote peers from290// corrupting or modifying the JSON output by putting special characters in291// their ver message.292obj.pushKV("subver", stats.cleanSubVer);293obj.pushKV("inbound", stats.fInbound);294obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to);295obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from);296obj.pushKV("presynced_headers", statestats.presync_height);297obj.pushKV("synced_headers", statestats.nSyncHeight);298obj.pushKV("synced_blocks", statestats.nCommonHeight);299UniValue heights(UniValue::VARR);300for (const int height : statestats.vHeightInFlight) {301heights.push_back(height);302}303obj.pushKV("inflight", std::move(heights));304obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled);305obj.pushKV("addr_processed", statestats.m_addr_processed);306obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited);307UniValue permissions(UniValue::VARR);308for (const auto& permission : NetPermissions::ToStrings(stats.m_permission_flags)) {309permissions.push_back(permission);310}311obj.pushKV("permissions", std::move(permissions));312obj.pushKV("minfeefilter", ValueFromAmount(statestats.m_fee_filter_received));314UniValue sendPerMsgType(UniValue::VOBJ);315for (const auto& [message_type, total_bytes] : stats.mapSendBytesPerMsgType) {316if (total_bytes > 0) {317sendPerMsgType.pushKVEnd(message_type, total_bytes);318}319}320obj.pushKV("bytessent_per_msg", std::move(sendPerMsgType));322UniValue recvPerMsgType(UniValue::VOBJ);323for (const auto& [message_type, total_bytes] : stats.mapRecvBytesPerMsgType) {324if (total_bytes > 0) {325recvPerMsgType.pushKVEnd(message_type, total_bytes);326}327}328obj.pushKV("bytesrecv_per_msg", std::move(recvPerMsgType));329obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));330obj.pushKV("transport_protocol_type", TransportTypeAsString(stats.m_transport_type));331obj.pushKV("session_id", stats.m_session_id);333ret.push_back(std::move(obj));334}336return ret;337},338};339}341static RPCMethod addnode()342{343return RPCMethod{344"addnode",345"Attempts to add or remove a node from the addnode list.\n"346"Or try a connection to a node once.\n"347"Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"348"full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n" +349strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) +350" and are counted separately from the -maxconnections limit.\n",351{352{"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address/hostname optionally followed by :port of the peer to connect to"},353{"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},354{"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol (ignored for 'remove' command)"},355},356RPCResult{RPCResult::Type::NONE, "", ""},357RPCExamples{358HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\" true")359+ HelpExampleRpc("addnode", R"("192.168.0.6:8333", "onetry", true)")360},361[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue362{363const auto command{self.Arg<std::string_view>("command")};364if (command != "onetry" && command != "add" && command != "remove") {365throw std::runtime_error(366self.ToString());367}369NodeContext& node = EnsureAnyNodeContext(request.context);370CConnman& connman = EnsureConnman(node);372const auto node_arg{self.Arg<std::string_view>("node")};373if (TrimStringView(node_arg).empty()) {374// Such a node would never resolve, but would be retried indefinitely.375throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Node address cannot be empty");376}378bool node_v2transport = connman.GetLocalServices() & NODE_P2P_V2;379bool use_v2transport = self.MaybeArg<bool>("v2transport").value_or(node_v2transport);381if (use_v2transport && !node_v2transport) {382throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: v2transport requested but not enabled (see -v2transport)");383}385if (command == "onetry")386{387CAddress addr;388connman.OpenNetworkConnection(/*addrConnect=*/addr,389/*fCountFailure=*/false,390/*grant_outbound=*/{},391/*pszDest=*/std::string{node_arg}.c_str(),392/*conn_type=*/ConnectionType::MANUAL,393/*use_v2transport=*/use_v2transport,394/*proxy_override=*/std::nullopt);395return UniValue::VNULL;396}398if (command == "add")399{400if (!connman.AddNode({std::string{node_arg}, use_v2transport})) {401throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");402}403}404else if (command == "remove")405{406if (!connman.RemoveAddedNode(node_arg)) {407throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously.");408}409}411return UniValue::VNULL;412},413};414}416static RPCMethod addconnection()417{418return RPCMethod{419"addconnection",420"Open an outbound connection to a specified node. This RPC is for testing only.\n",421{422{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},423{"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open (\"outbound-full-relay\", \"block-relay-only\", \"addr-fetch\" or \"feeler\")."},424{"v2transport", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Attempt to connect using BIP324 v2 transport protocol"},425},426RPCResult{427RPCResult::Type::OBJ, "", "",428{429{ RPCResult::Type::STR, "address", "Address of newly added connection." },430{ RPCResult::Type::STR, "connection_type", "Type of connection opened." },431}},432RPCExamples{433HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true")434+ HelpExampleRpc("addconnection", R"("192.168.0.6:8333", "outbound-full-relay", true)")435},436[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue437{438if (Params().GetChainType() != ChainType::REGTEST) {439throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");440}442const std::string address = request.params[0].get_str();443auto conn_type_in{util::TrimStringView(self.Arg<std::string_view>("connection_type"))};444ConnectionType conn_type{};445if (conn_type_in == "outbound-full-relay") {446conn_type = ConnectionType::OUTBOUND_FULL_RELAY;447} else if (conn_type_in == "block-relay-only") {448conn_type = ConnectionType::BLOCK_RELAY;449} else if (conn_type_in == "addr-fetch") {450conn_type = ConnectionType::ADDR_FETCH;451} else if (conn_type_in == "feeler") {452conn_type = ConnectionType::FEELER;453} else {454throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());455}456bool use_v2transport{self.Arg<bool>("v2transport")};458NodeContext& node = EnsureAnyNodeContext(request.context);459CConnman& connman = EnsureConnman(node);461if (use_v2transport && !(connman.GetLocalServices() & NODE_P2P_V2)) {462throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Adding v2transport connections requires -v2transport init flag to be set.");463}465const bool success = connman.AddConnection(address, conn_type, use_v2transport);466if (!success) {467throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type.");468}470UniValue info(UniValue::VOBJ);471info.pushKV("address", address);472info.pushKV("connection_type", conn_type_in);474return info;475},476};477}479static RPCMethod disconnectnode()480{481return RPCMethod{482"disconnectnode",483"Immediately disconnects from the specified peer node.\n"484"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"485"\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",486{487{"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"},488{"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"},489},490RPCResult{RPCResult::Type::NONE, "", ""},491RPCExamples{492HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")493+ HelpExampleCli("disconnectnode", "\"\" 1")494+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")495+ HelpExampleRpc("disconnectnode", "\"\", 1")496},497[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue498{499NodeContext& node = EnsureAnyNodeContext(request.context);500CConnman& connman = EnsureConnman(node);