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.
1001[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1002{1003NodeContext& node = EnsureAnyNodeContext(request.context);1004const CConnman& connman = EnsureConnman(node);1006const int count{request.params[0].isNull() ? 1 : request.params[0].getInt<int>()};1007if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");1009const std::optional<Network> network{request.params[1].isNull() ? std::nullopt : std::optional<Network>{ParseNetwork(request.params[1].get_str())}};1010if (network == NET_UNROUTABLE) {1011throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str()));1012}1014// returns a shuffled list of CAddress1015const std::vector<CAddress> vAddr{connman.GetAddressesUnsafe(count, /*max_pct=*/0, network)};1016UniValue ret(UniValue::VARR);1018for (const CAddress& addr : vAddr) {1019UniValue obj(UniValue::VOBJ);1020obj.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(addr.nTime));1021obj.pushKV("services", static_cast<std::underlying_type_t<decltype(addr.nServices)>>(addr.nServices));1022obj.pushKV("address", addr.ToStringAddr());1023obj.pushKV("port", addr.GetPort());1024obj.pushKV("network", GetNetworkName(addr.GetNetClass()));1025ret.push_back(std::move(obj));1026}1027return ret;1028},1029};1030}1032static RPCMethod addpeeraddress()1033{1034return RPCMethod{"addpeeraddress",1035"Add the address of a potential peer to an address manager table. This RPC is for testing only.",1036{1037{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},1038{"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"},1039{"tried", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, attempt to add the peer to the tried addresses table"},1040},1041RPCResult{1042RPCResult::Type::OBJ, "", "",1043{1044{RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager table"},1045{RPCResult::Type::STR, "error", /*optional=*/true, "error description, if the address could not be added"},1046},1047},1048RPCExamples{1049HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333 true")1050+ HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333, true")1051},1052[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1053{1054AddrMan& addrman = EnsureAnyAddrman(request.context);1056const std::string& addr_string{request.params[0].get_str()};1057const auto port{request.params[1].getInt<uint16_t>()};1058const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()};1060UniValue obj(UniValue::VOBJ);1061std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};1062if (!net_addr.has_value()) {1063throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Invalid IP address");1064}1066bool success{false};1068CService service{net_addr.value(), port};1069CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};1070address.nTime = Now<NodeSeconds>();1071// The source address is set equal to the address. This is equivalent to the peer1072// announcing itself.1073if (addrman.Add({address}, address)) {1074success = true;1075if (tried) {1076// Attempt to move the address to the tried addresses table.1077if (!addrman.Good(address)) {1078success = false;1079obj.pushKV("error", "failed-adding-to-tried");1080}1081}1082} else {1083obj.pushKV("error", "failed-adding-to-new");1084}1086obj.pushKV("success", success);1087return obj;1088},1089};1090}1092static RPCMethod sendmsgtopeer()1093{1094return RPCMethod{1095"sendmsgtopeer",1096"Send a p2p message to a peer specified by id.\n"1097"The message type and body must be provided, the message header will be generated.\n"1098"This RPC is for testing only.",1099{1100{"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to send the message to."},1101{"msg_type", RPCArg::Type::STR, RPCArg::Optional::NO, strprintf("The message type (maximum length %i)", CMessageHeader::MESSAGE_TYPE_SIZE)},1102{"msg", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized message body to send, in hex, without a message header"},1103},1104RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},1105RPCExamples{1106HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", R"(0, "addr", "ffffff")")},1107[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {1108const NodeId peer_id{request.params[0].getInt<int64_t>()};1109const auto msg_type{self.Arg<std::string_view>("msg_type")};1110if (msg_type.size() > CMessageHeader::MESSAGE_TYPE_SIZE) {1111throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::MESSAGE_TYPE_SIZE));1112}1113auto msg{TryParseHex<unsigned char>(self.Arg<std::string_view>("msg"))};1114if (!msg.has_value()) {1115throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg");1116}1118NodeContext& node = EnsureAnyNodeContext(request.context);1119CConnman& connman = EnsureConnman(node);1121CSerializedNetMsg msg_ser;1122msg_ser.data = msg.value();1123msg_ser.m_type = msg_type;1125bool success = connman.ForNode(peer_id, [&](CNode* node) {1126connman.PushMessage(node, std::move(msg_ser));1127return true;1128});1130if (!success) {1131throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not send message to peer");1132}1134UniValue ret{UniValue::VOBJ};1135return ret;1136},1137};1138}1140static RPCMethod getaddrmaninfo()1141{1142return RPCMethod{1143"getaddrmaninfo",1144"Provides information about the node's address manager by returning the number of "1145"addresses in the `new` and `tried` tables and their sum for all networks.\n",1146{},1147RPCResult{1148RPCResult::Type::OBJ_DYN, "", "json object with network type as keys", {1149{RPCResult::Type::OBJ, "network", "the network (" + Join(GetNetworkNames(), ", ") + ", all_networks)", {1150{RPCResult::Type::NUM, "new", "number of addresses in the new table, which represent potential peers the node has discovered but hasn't yet successfully connected to."},1151{RPCResult::Type::NUM, "tried", "number of addresses in the tried table, which represent peers the node has successfully connected to in the past."},1152{RPCResult::Type::NUM, "total", "total number of addresses in both new/tried tables"},1153}},1154}},1155RPCExamples{HelpExampleCli("getaddrmaninfo", "") + HelpExampleRpc("getaddrmaninfo", "")},1156[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {1157AddrMan& addrman = EnsureAnyAddrman(request.context);1159UniValue ret(UniValue::VOBJ);1160for (int n = 0; n < NET_MAX; ++n) {1161enum Network network = static_cast<enum Network>(n);1162if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;1163UniValue obj(UniValue::VOBJ);1164obj.pushKV("new", addrman.Size(network, true));1165obj.pushKV("tried", addrman.Size(network, false));1166obj.pushKV("total", addrman.Size(network));1167ret.pushKV(GetNetworkName(network), std::move(obj));1168}1169UniValue obj(UniValue::VOBJ);1170obj.pushKV("new", addrman.Size(std::nullopt, true));1171obj.pushKV("tried", addrman.Size(std::nullopt, false));1172obj.pushKV("total", addrman.Size());1173ret.pushKV("all_networks", std::move(obj));1174return ret;1175},1176};1177}1179static RPCMethod exportasmap()1180{1181return RPCMethod{1182"exportasmap",1183"Export the embedded ASMap data to a file. Any existing file at the path will be overwritten.\n",1184{1185{"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},1186},1187RPCResult{1188RPCResult::Type::OBJ, "", "",1189{1190{RPCResult::Type::STR, "path", "the absolute path that the ASMap data was written to"},1191{RPCResult::Type::NUM, "bytes_written", "the number of bytes written to the file"},1192{RPCResult::Type::STR_HEX, "file_hash", "the SHA256 hash of the exported ASMap data"},1193}1194},1195RPCExamples{1196HelpExampleCli("exportasmap", "\"asmap.dat\"") + HelpExampleRpc("exportasmap", "\"asmap.dat\"")},1197[&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {1198#ifndef ENABLE_EMBEDDED_ASMAP1199throw JSONRPCError(RPC_MISC_ERROR, "No embedded ASMap data available");1200#else1201if (node::data::ip_asn.empty() || !CheckStandardAsmap(node::data::ip_asn)) {1202throw JSONRPCError(RPC_MISC_ERROR, "Embedded ASMap data appears to be corrupted");1203}1205const ArgsManager& args{EnsureAnyArgsman(request.context)};1206const fs::path export_path{fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg<std::string_view>("path")))};1208AutoFile file{fsbridge::fopen(export_path, "wb")};1209if (file.IsNull()) {1210throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to open asmap file: %s", fs::PathToString(export_path)));1211}1213file << node::data::ip_asn;1215if (file.fclose() != 0) {1216throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to close asmap file: %s", fs::PathToString(export_path)));1217}1219UniValue result(UniValue::VOBJ);1220result.pushKV("path", export_path.utf8string());1221result.pushKV("bytes_written", node::data::ip_asn.size());1222result.pushKV("file_hash", HexStr(AsmapVersion(node::data::ip_asn)));1223return result;1224#endif1225},1226};1227}1229UniValue AddrmanEntryToJSON(const AddrInfo& info, const CConnman& connman)1230{1231UniValue ret(UniValue::VOBJ);1232ret.pushKV("address", info.ToStringAddr());1233const uint32_t mapped_as{connman.GetMappedAS(info)};1234if (mapped_as) {1235ret.pushKV("mapped_as", mapped_as);1236}1237ret.pushKV("port", info.GetPort());1238ret.pushKV("services", static_cast<std::underlying_type_t<decltype(info.nServices)>>(info.nServices));1239ret.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(info.nTime));1240ret.pushKV("network", GetNetworkName(info.GetNetClass()));1241ret.pushKV("source", info.source.ToStringAddr());1242ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass()));1243const uint32_t source_mapped_as{connman.GetMappedAS(info.source)};1244if (source_mapped_as) {1245ret.pushKV("source_mapped_as", source_mapped_as);1246}1247return ret;1248}1250UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos, const CConnman& connman)