aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-10-03 11:29:58 -0400
committerAndrew Chow <github@achow101.com>2023-10-03 11:38:20 -0400
commit01bd9d7b991bf8b79748ba5b3c76839a0d3bb5a4 (patch)
tree5678ca8aebbb30a6cc1bbfef2381056f96559abb /src
parent5a4eb56e3fc47fd44dd2efbc55509d0663f9a47c (diff)
parent352d5eb2a9e89cff4a2815d94a9d81fcc20c4b2c (diff)
downloadbitcoin-01bd9d7b991bf8b79748ba5b3c76839a0d3bb5a4.tar.xz
Merge bitcoin/bitcoin#28523: rpc: add hidden getrawaddrman RPC to list addrman table entries
352d5eb2a9e89cff4a2815d94a9d81fcc20c4b2c test: getrawaddrman RPC (0xb10c) da384a286bd84a97e7ebe7a64654c5be20ab2df1 rpc: getrawaddrman for addrman entries (0xb10c) Pull request description: Inspired by `getaddrmaninfo` (#27511), this adds a hidden/test-only `getrawaddrman` RPC. The RPC returns information on all addresses in the address manager new and tried tables. Addrman table contents can be used in tests and during development. The RPC result encodes the `bucket` and `position`, the internal location of addresses in the tables, in the address object's string key. This allows users to choose to consume or to ignore the location information. If the internals of the address manager implementation change, the location encoding might change too. ``` getrawaddrman EXPERIMENTAL warning: this call may be changed in future releases. Returns information on all address manager entries for the new and tried tables. Result: { (json object) "table" : { (json object) buckets with addresses in the address manager table ( new, tried ) "bucket/position" : { (json object) the location in the address manager table (<bucket>/<position>) "address" : "str", (string) The address of the node "port" : n, (numeric) The port number of the node "network" : "str", (string) The network (ipv4, ipv6, onion, i2p, cjdns) of the address "services" : n, (numeric) The services offered by the node "time" : xxx, (numeric) The UNIX epoch time when the node was last seen "source" : "str", (string) The address that relayed the address to us "source_network" : "str" (string) The network (ipv4, ipv6, onion, i2p, cjdns) of the source address }, ... }, ... } Examples: > bitcoin-cli getrawaddrman > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getrawaddrman", "params": []}' -H 'content-type: text/plain;' http://127.0.0.1:8332/ ``` ACKs for top commit: willcl-ark: reACK 352d5eb2a9 amitiuttarwar: reACK 352d5eb2a9e stratospher: reACK 352d5eb. achow101: ACK 352d5eb2a9e89cff4a2815d94a9d81fcc20c4b2c Tree-SHA512: cc462666b5c709617c66b0e3e9a17c4c81e9e295f91bdd9572492d1cb6466fc9b6d48ee805ebe82f9f16010798370effe5c8f4db15065b8c7c0d8637675d615e
Diffstat (limited to 'src')
-rw-r--r--src/addrman.cpp38
-rw-r--r--src/addrman.h14
-rw-r--r--src/addrman_impl.h5
-rw-r--r--src/rpc/net.cpp70
-rw-r--r--src/test/fuzz/rpc.cpp1
5 files changed, 127 insertions, 1 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 212baab9d4..6ce9c81c63 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -838,6 +838,30 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
return addresses;
}
+std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries_(bool from_tried) const
+{
+ AssertLockHeld(cs);
+
+ const int bucket_count = from_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT;
+ std::vector<std::pair<AddrInfo, AddressPosition>> infos;
+ for (int bucket = 0; bucket < bucket_count; ++bucket) {
+ for (int position = 0; position < ADDRMAN_BUCKET_SIZE; ++position) {
+ int id = GetEntry(from_tried, bucket, position);
+ if (id >= 0) {
+ AddrInfo info = mapInfo.at(id);
+ AddressPosition location = AddressPosition(
+ from_tried,
+ /*multiplicity_in=*/from_tried ? 1 : info.nRefCount,
+ bucket,
+ position);
+ infos.push_back(std::make_pair(info, location));
+ }
+ }
+ }
+
+ return infos;
+}
+
void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)
{
AssertLockHeld(cs);
@@ -1199,6 +1223,15 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct,
return addresses;
}
+std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries(bool from_tried) const
+{
+ LOCK(cs);
+ Check();
+ auto addrInfos = GetEntries_(from_tried);
+ Check();
+ return addrInfos;
+}
+
void AddrManImpl::Connected(const CService& addr, NodeSeconds time)
{
LOCK(cs);
@@ -1289,6 +1322,11 @@ std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std
return m_impl->GetAddr(max_addresses, max_pct, network);
}
+std::vector<std::pair<AddrInfo, AddressPosition>> AddrMan::GetEntries(bool use_tried) const
+{
+ return m_impl->GetEntries(use_tried);
+}
+
void AddrMan::Connected(const CService& addr, NodeSeconds time)
{
m_impl->Connected(addr, time);
diff --git a/src/addrman.h b/src/addrman.h
index f41687dcff..4d44c943ac 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -25,11 +25,12 @@ public:
};
class AddrManImpl;
+class AddrInfo;
/** Default for -checkaddrman */
static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
-/** Test-only struct, capturing info about an address in AddrMan */
+/** Location information for an address in AddrMan */
struct AddressPosition {
// Whether the address is in the new or tried table
const bool tried;
@@ -168,6 +169,17 @@ public:
*/
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
+ /**
+ * Returns an information-location pair for all addresses in the selected addrman table.
+ * If an address appears multiple times in the new table, an information-location pair
+ * is returned for each occurence. Addresses only ever appear once in the tried table.
+ *
+ * @param[in] from_tried Selects which table to return entries from.
+ *
+ * @return A vector consisting of pairs of AddrInfo and AddressPosition.
+ */
+ std::vector<std::pair<AddrInfo, AddressPosition>> GetEntries(bool from_tried) const;
+
/** We have successfully connected to this peer. Calling this function
* updates the CAddress's nTime, which is used in our IsTerrible()
* decisions and gossiped to peers. Callers should be careful that updating
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 1cfaca04a3..512f085a21 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -132,6 +132,9 @@ public:
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
+ std::vector<std::pair<AddrInfo, AddressPosition>> GetEntries(bool from_tried) const
+ EXCLUSIVE_LOCKS_REQUIRED(!cs);
+
void Connected(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
@@ -260,6 +263,8 @@ private:
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::vector<std::pair<AddrInfo, AddressPosition>> GetEntries_(bool from_tried) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
void Connected_(const CService& addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 8d796b8e9b..96d06b6b9f 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -5,6 +5,7 @@
#include <rpc/server.h>
#include <addrman.h>
+#include <addrman_impl.h>
#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
@@ -1079,6 +1080,74 @@ static RPCHelpMan getaddrmaninfo()
};
}
+UniValue AddrmanEntryToJSON(const AddrInfo& info)
+{
+ UniValue ret(UniValue::VOBJ);
+ ret.pushKV("address", info.ToStringAddr());
+ ret.pushKV("port", info.GetPort());
+ ret.pushKV("services", (uint64_t)info.nServices);
+ ret.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(info.nTime)});
+ ret.pushKV("network", GetNetworkName(info.GetNetClass()));
+ ret.pushKV("source", info.source.ToStringAddr());
+ ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass()));
+ return ret;
+}
+
+UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos)
+{
+ UniValue table(UniValue::VOBJ);
+ for (const auto& e : tableInfos) {
+ AddrInfo info = e.first;
+ AddressPosition location = e.second;
+ std::ostringstream key;
+ key << location.bucket << "/" << location.position;
+ // Address manager tables have unique entries so there is no advantage
+ // in using UniValue::pushKV, which checks if the key already exists
+ // in O(N). UniValue::pushKVEnd is used instead which currently is O(1).
+ table.pushKVEnd(key.str(), AddrmanEntryToJSON(info));
+ }
+ return table;
+}
+
+static RPCHelpMan getrawaddrman()
+{
+ return RPCHelpMan{"getrawaddrman",
+ "EXPERIMENTAL warning: this call may be changed in future releases.\n"
+ "\nReturns information on all address manager entries for the new and tried tables.\n",
+ {},
+ RPCResult{
+ RPCResult::Type::OBJ_DYN, "", "", {
+ {RPCResult::Type::OBJ_DYN, "table", "buckets with addresses in the address manager table ( new, tried )", {
+ {RPCResult::Type::OBJ, "bucket/position", "the location in the address manager table (<bucket>/<position>)", {
+ {RPCResult::Type::STR, "address", "The address of the node"},
+ {RPCResult::Type::NUM, "port", "The port number of the node"},
+ {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the address"},
+ {RPCResult::Type::NUM, "services", "The services offered by the node"},
+ {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"},
+ {RPCResult::Type::STR, "source", "The address that relayed the address to us"},
+ {RPCResult::Type::STR, "source_network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the source address"},
+ }}
+ }}
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("getrawaddrman", "")
+ + HelpExampleRpc("getrawaddrman", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ if (!node.addrman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Address manager functionality missing or disabled");
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.pushKV("new", AddrmanTableToJSON(node.addrman->GetEntries(false)));
+ ret.pushKV("tried", AddrmanTableToJSON(node.addrman->GetEntries(true)));
+ return ret;
+ },
+ };
+}
+
void RegisterNetRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
@@ -1099,6 +1168,7 @@ void RegisterNetRPCCommands(CRPCTable& t)
{"hidden", &addpeeraddress},
{"hidden", &sendmsgtopeer},
{"hidden", &getaddrmaninfo},
+ {"hidden", &getrawaddrman},
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 27bb60d6b6..270cab58e2 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -142,6 +142,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"getnodeaddresses",
"getpeerinfo",
"getprioritisedtransactions",
+ "getrawaddrman",
"getrawmempool",
"getrawtransaction",
"getrpcinfo",