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

Code before:
        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 {
            AddrMan& addrman = EnsureAnyAddrman(request.context);

            UniValue ret(UniValue::VOBJ);
            ret.pushKV("new", AddrmanTableToJSON(addrman.GetEntries(false)));
            ret.pushKV("tried", AddrmanTableToJSON(addrman.GetEntries(true)));
            return ret;
        },
    };
}

void RegisterNetRPCCommands(CRPCTable& t)
{
    static const CRPCCommand commands[]{

Review comment (suggestion):
Here and in the other new help below, the reason for the optional nature of this field could perhaps be mentioned (as simply as `, if present`, or perhaps in more detail).

```suggestion
                        {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "The ASN mapped to the IP of this peer per our current ASMap, if present"},
```

Code after:
    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, connman));
    }
    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, "mapped_as", /*optional=*/true, "The ASN mapped to the IP of this peer per our current ASMap"},
                        {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"},
                        {RPCResult::Type::NUM, "source_mapped_as", /*optional=*/true, "The ASN mapped to the IP of this peer's source per our current ASMap"}
                    }}
                }}
            }
        },
        RPCExamples{
            HelpExampleCli("getrawaddrman", "")
            + HelpExampleRpc("getrawaddrman", "")
        },
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
            AddrMan& addrman = EnsureAnyAddrman(request.context);
            NodeContext& node_context = EnsureAnyNodeContext(request.context);
            CConnman& connman = EnsureConnman(node_context);

            UniValue ret(UniValue::VOBJ);
            ret.pushKV("new", AddrmanTableToJSON(addrman.GetEntries(false), connman));
            ret.pushKV("tried", AddrmanTableToJSON(addrman.GetEntries(true), connman));
            return ret;
        },