Repository: bitcoin/bitcoin
File: src/rpc/net.cpp (C++)

Code before:
            }},
        }},
        RPCExamples{HelpExampleCli("getaddrmaninfo", "") + HelpExampleRpc("getaddrmaninfo", "")},
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
            AddrMan& addrman = EnsureAnyAddrman(request.context);

            UniValue ret(UniValue::VOBJ);
            for (int n = 0; n < NET_MAX; ++n) {
                enum Network network = static_cast<enum Network>(n);
                if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
                UniValue obj(UniValue::VOBJ);
                obj.pushKV("new", addrman.Size(network, true));
                obj.pushKV("tried", addrman.Size(network, false));
                obj.pushKV("total", addrman.Size(network));
                ret.pushKV(GetNetworkName(network), obj);
            }
            UniValue obj(UniValue::VOBJ);
            obj.pushKV("new", addrman.Size(std::nullopt, true));
            obj.pushKV("tried", addrman.Size(std::nullopt, false));
            obj.pushKV("total", addrman.Size());
            ret.pushKV("all_networks", obj);
            return ret;
        },
    };
}

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));

Review comment (suggestion):
Using `auto` here requires looking up `GetMappedAS` to know the type (at least, for people using simple editors and not fancier IDEs). Using the actual type in this case would have been clearer to the reader. The conditional could also have been simpler, though that's arguably a style nit.

```diff
-    const auto mapped_as{connman.GetMappedAS(info)};
-    if (mapped_as != 0) {
+    const uint32_t mapped_as{connman.GetMappedAS(info)};
+    if (mapped_as) {
```


Code after:
            UniValue ret(UniValue::VOBJ);
            for (int n = 0; n < NET_MAX; ++n) {
                enum Network network = static_cast<enum Network>(n);
                if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
                UniValue obj(UniValue::VOBJ);
                obj.pushKV("new", addrman.Size(network, true));
                obj.pushKV("tried", addrman.Size(network, false));
                obj.pushKV("total", addrman.Size(network));
                ret.pushKV(GetNetworkName(network), obj);
            }
            UniValue obj(UniValue::VOBJ);
            obj.pushKV("new", addrman.Size(std::nullopt, true));
            obj.pushKV("tried", addrman.Size(std::nullopt, false));
            obj.pushKV("total", addrman.Size());
            ret.pushKV("all_networks", obj);
            return ret;
        },
    };
}

UniValue AddrmanEntryToJSON(const AddrInfo& info, CConnman& connman)
{
    UniValue ret(UniValue::VOBJ);
    ret.pushKV("address", info.ToStringAddr());
    const auto mapped_as{connman.GetMappedAS(info)};
    if (mapped_as != 0) {
        ret.pushKV("mapped_as", mapped_as);
    }
    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()));
    const auto source_mapped_as{connman.GetMappedAS(info.source)};
    if (source_mapped_as != 0) {
        ret.pushKV("source_mapped_as", source_mapped_as);
    }
    return ret;
}

UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos, CConnman& connman)
{
    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