p2p, rpc: enable GetAddr, GetAddresses, and getnodeaddresses by network #21843

pull jonatack wants to merge 7 commits into bitcoin:master from jonatack:getnodeaddresses-by-network changing 12 files +114 −47
  1. jonatack commented at 11:38 am on May 3, 2021: member

    This patch allows passing a network argument to CAddrMan::GetAddr(), CConnman::GetAddresses(), and rpc getnodeaddresses to return only addresses of that network.

    It also contains a performance optimisation by promag to no longer call gettime for each vRandom entry inside the CAddrMan::GetAddr_() loop.

  2. fanquake added the label P2P on May 3, 2021
  3. jonatack renamed this:
    net, rpc: enable GetAddr, GetAddresses, and getnodeaddresses by network
    p2p, rpc: enable GetAddr, GetAddresses, and getnodeaddresses by network
    on May 3, 2021
  4. in src/rpc/net.cpp:884 in faa28f6ece outdated
    878@@ -875,8 +879,13 @@ static RPCHelpMan getnodeaddresses()
    879     const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()};
    880     if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
    881 
    882+    const Network network{request.params[1].isNull() ? Network::NET_MAX : ParseNetwork(request.params[1].get_str())};
    883+    if (network == NET_UNROUTABLE) {
    884+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid network (not recognized)");
    


    vasild commented at 12:10 pm on May 3, 2021:

    Maybe print the unrecognized string:

    0        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str());
    

    jonatack commented at 7:22 pm on May 3, 2021:
    Good idea! Done.
  5. in src/addrman.h:719 in faa28f6ece outdated
    715@@ -716,13 +716,13 @@ friend class CAddrManTest;
    716     }
    717 
    718     //! Return a bunch of addresses, selected at random.
    719-    std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct)
    720+    std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, Network net = Network::NET_MAX)
    


    vasild commented at 12:13 pm on May 3, 2021:
    To designate “not specified / any network”, maybe std::optional would fit better than using the special value NET_MAX? I plan to remove NET_MAX some day.

    jonatack commented at 12:22 pm on May 3, 2021:
    I was asking myself if std::optional would be better here. Thanks!
  6. in src/addrman.h:282 in faa28f6ece outdated
    278@@ -279,7 +279,7 @@ friend class CAddrManTest;
    279 #endif
    280 
    281     //! Select several addresses at once.
    282-    void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs);
    283+    void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct, Network net = Network::NET_MAX) EXCLUSIVE_LOCKS_REQUIRED(cs);
    


    vasild commented at 12:16 pm on May 3, 2021:

    The default value can be removed since all callers of this method always provide the argument.

    0    void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct, Network net) EXCLUSIVE_LOCKS_REQUIRED(cs);
    

    jonatack commented at 7:23 pm on May 3, 2021:
    Indeed! Done.

    jonatack commented at 7:23 pm on May 3, 2021:
    Indeed! Done.
  7. vasild commented at 12:20 pm on May 3, 2021: member

    Approach ACK.

    Filtering this “server side” would help reduce network traffic especially if all addresses are requested (matters if the RPC client is not running on the same machine as bitcoind). It does not add any (measurable) computational overhead on the “server side”.

  8. jonatack force-pushed on May 3, 2021
  9. jonatack force-pushed on May 3, 2021
  10. jonatack marked this as ready for review on May 3, 2021
  11. jonatack commented at 11:00 pm on May 3, 2021: member
    Thanks for the early feedback @vasild! Updated and ready for review.
  12. DrahtBot commented at 0:13 am on May 4, 2021: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #21941 (fuzz: Call const member functions in addrman fuzz test only once by MarcoFalke)
    • #21940 (refactor: Mark CAddrMan::Select const by MarcoFalke)
    • #20833 (rpc/validation: enable packages through testmempoolaccept by glozow)
    • #18722 (addrman: improve performance by using more suitable containers by vasild)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  13. in src/addrman.h:733 in ac01ec096b outdated
    730+     *
    731+     * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
    732+     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
    733+     * @param[in] network        Select only addresses of this network (nullopt = all).
    734+     */
    735+    std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network = std::nullopt)
    


    vasild commented at 7:10 am on May 4, 2021:

    It just occurred to me that the only (non test) caller of GetAddr() is GetAddresses() which will always pass 3 arguments. Maybe consider removing the default from here since it is not necessary.

    0    std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
    

    jonatack commented at 9:21 am on May 4, 2021:
    Good idea, doing (this will add fuzz coverage for change too).
  14. in test/functional/rpc_net.py:226 in ac01ec096b outdated
    248 
    249-        # addrman's size cannot be known reliably after insertion, as hash collisions may occur
    250-        # so only test that requesting a large number of addresses returns less than that
    251-        LARGE_REQUEST_COUNT = 10000
    252-        node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT)
    253-        assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses))
    


    vasild commented at 7:23 am on May 4, 2021:
    Why remove this test?

    jonatack commented at 8:53 am on May 4, 2021:
    It’s redundant with the assertion in line 215 (before this change they were two identical tests as well, by two different authors).
  15. in doc/release-notes.md:134 in ac01ec096b outdated
    135@@ -130,9 +136,6 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect
    136 
    137 - Passing an invalid `-rpcauth` argument now cause bitcoind to fail to start.  (#20461)
    138 
    139-- The `getnodeaddresses` RPC now returns a "network" field indicating the
    140-  network type (ipv4, ipv6, onion, or i2p) for each address.  (#21594)
    


    vasild commented at 7:27 am on May 4, 2021:
    This move is unrelated to this PR. If this PR does not fly, when the move will not fly either.

    jonatack commented at 9:00 am on May 4, 2021:
    I think it’s ok. If this PR doesn’t make the release, I can move the existing note to the right place when the notes are moved to the wiki for editing (I usually make some corrections in the wiki before the notes are moved back to the repo for -final).
  16. vasild approved
  17. vasild commented at 9:12 am on May 4, 2021: member

    ACK ac01ec096bc5ff437db5c4797e3d98b7a6efad23

    (would be happy to re-ACK if the default value of the 3rd arg of GetAddr() is removed)

  18. jonatack force-pushed on May 4, 2021
  19. jonatack commented at 4:39 pm on May 4, 2021: member
    Thank you @vasild. Removed the defaults and improved the fuzzing per git diff ac01ec0 09f2c20.
  20. jonatack force-pushed on May 5, 2021
  21. jonatack force-pushed on May 6, 2021
  22. jonatack commented at 7:10 am on May 6, 2021: member
    Rebased for CI fix on master.
  23. vasild commented at 12:44 pm on May 11, 2021: member
    The latest push removed the default value for the network argument from CAddrMan::GetAddr() and from CConnMan::GetAddresses() too. The latter deserves a default value because now there are a lot of call sites like connman.GetAddresses(..., std::nullopt), no?
  24. jonatack commented at 1:13 pm on May 11, 2021: member

    GetAddresses(…, std::nullopt)`

    Only in two places outside of tests, so it seemed better to pass it explicitly.

  25. in src/addrman.cpp:507 in 8d4b14e001 outdated
    502@@ -501,8 +503,10 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
    503         assert(mapInfo.count(vRandom[n]) == 1);
    504 
    505         const CAddrInfo& ai = mapInfo[vRandom[n]];
    506-        if (!ai.IsTerrible())
    507+        // Filter for quality, and if a network is passed, filter also by network.
    508+        if (!ai.IsTerrible() && (network == std::nullopt || ai.GetNetClass() == network)) {
    


    promag commented at 9:21 am on May 12, 2021:

    8d4b14e001ec026f346c6b4b00509adae7769415

    I’d use a different approach to not mix different conditions:

    0// Filter by network (optional)
    1if (network != std::nullopt && ai.GetNetClass() != network) continue;
    2
    3// Filter for quality
    4if (ai.IsTerrible()) continue;
    5
    6vAddr.push_back(ai);
    

    Also note that it first filters by network, which I think is slightly better.

    I also want to point that IsTerrible default argument is computed in each iteration, I’d suggest:

    0    const int64_t now = GetAdjustedTime();
    1
    2    // gather a list of random nodes, skipping those of low quality
    3    for (unsigned int n = 0; n < vRandom.size(); n++) {
    4       ...
    5       if (ai.IsTerrible(now)) continue;
    

    jonatack commented at 3:25 pm on May 12, 2021:
    Thanks @promag, done and added a commit by you for the gettime optimization.
  26. in src/addrman.h:733 in 8942494e8c outdated
    730+     *
    731+     * @param[in] max_addresses  Maximum number of addresses to return (0 = all).
    732+     * @param[in] max_pct        Maximum percentage of addresses to return (0 = all).
    733+     * @param[in] network        Select only addresses of this network (nullopt = all).
    734+     */
    735+    std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
    


    promag commented at 9:25 am on May 12, 2021:

    8942494e8c5eff8a3e268fe830868faf8ce19f9f

    Why not network = std::nullopt? It would avoid changes in call sites.


    jonatack commented at 9:36 am on May 12, 2021:
    Yes, that is what the PR initially did, as it was a smaller diff and I tend to start with the smaller change. It is now passed explicitly in reponse to review feedback. I agree that explicit is good too.

    promag commented at 9:43 am on May 12, 2021:
    You can dismiss my comment, just checked @vasild comment #21843 (review).
  27. promag commented at 9:29 am on May 12, 2021: member

    Concept ACK.

    I think this change could be simplified by setting the default argument of the network filter.

  28. vasild approved
  29. vasild commented at 1:08 pm on May 12, 2021: member

    ACK bdc57fc120affcd255b5b79b505433f5ed4dc843

    Whether to have a default value for the argument of CAddrMan::GetAddr() and CConnMan::GetAddresses() is not a showstopper for this PR, IMO.

    Now there are two non-test callers of GetAddresses() that explicitly pass nullopt:

    https://github.com/bitcoin/bitcoin/blob/bdc57fc120affcd255b5b79b505433f5ed4dc843/src/net.cpp#L2691

    https://github.com/bitcoin/bitcoin/blob/bdc57fc120affcd255b5b79b505433f5ed4dc843/src/net_processing.cpp#L3580

  30. jonatack force-pushed on May 12, 2021
  31. jonatack commented at 3:29 pm on May 12, 2021: member
    Thanks @vasild, agreed. Making them explicit was more work, but I reckon sooner or later someone is going to make them explicit so may as well do it now.
  32. jonatack commented at 3:32 pm on May 12, 2021: member

    Only change is @promag’s suggestion: git diff bdc57fc 9d17f30

     0diff --git a/src/addrman.cpp b/src/addrman.cpp
     1index 473ac21ad0..ceab1689d7 100644
     2--- a/src/addrman.cpp
     3+++ b/src/addrman.cpp
     4@@ -494,6 +494,7 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
     5+    const int64_t now{GetAdjustedTime()};
     6     for (unsigned int n = 0; n < vRandom.size(); n++) {
     7         if (vAddr.size() >= nNodes)
     8             break;
     9@@ -503,10 +504,14 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
    10         assert(mapInfo.count(vRandom[n]) == 1);
    11 
    12         const CAddrInfo& ai = mapInfo[vRandom[n]];
    13-        // Filter for quality, and if a network is passed, filter also by network.
    14-        if (!ai.IsTerrible() && (network == std::nullopt || ai.GetNetClass() == network)) {
    15-            vAddr.push_back(ai);
    16-        }
    17+
    18+        // Filter by network (optional)
    19+        if (network != std::nullopt && ai.GetNetClass() != network) continue;
    20+
    21+        // Filter for quality
    22+        if (ai.IsTerrible(now)) continue;
    23+
    24+        vAddr.push_back(ai);
    25     }
    26 }
    
  33. promag commented at 3:41 pm on May 12, 2021: member
    Code review ACK 9d17f30c7e281d0f424eb45129beb6a6e62e37b9.
  34. vasild approved
  35. vasild commented at 4:42 pm on May 12, 2021: member
    ACK 9d17f30c7e281d0f424eb45129beb6a6e62e37b9
  36. DrahtBot added the label Needs rebase on May 19, 2021
  37. p2p: enable CAddrMan::GetAddr_() by network, add doxygen d35ddca91e
  38. p2p: pull time call out of loop in CAddrMan::GetAddr_() c38981e748
  39. p2p: allow CAddrMan::GetAddr() by network, add doxygen a49f3ddbba
  40. p2p: allow CConnman::GetAddresses() by network, add doxygen 80ba294854
  41. rpc: enable filtering getnodeaddresses by network 6c98c09991
  42. test: improve getnodeaddresses coverage, test by network 3f89c0e990
  43. doc: release note for getnodeaddresses by network ce6bca88e8
  44. jonatack commented at 11:10 am on May 19, 2021: member

    rebased after merge of #21506, no other change

    git range-diff 4da26fb 9d17f30 ce6bca8

    0     @@ src/net_processing.cpp: void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
    1              pfrom.vAddrToSend.clear();
    2              std::vector<CAddress> vAddr;
    3-         if (pfrom.HasPermission(PF_ADDR)) {
    4+         if (pfrom.HasPermission(NetPermissionFlags::Addr)) {
    5              vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND, /* network */ std::nullopt);
    
  45. jonatack force-pushed on May 19, 2021
  46. vasild approved
  47. vasild commented at 11:20 am on May 19, 2021: member
    ACK ce6bca88e8c685c69686e0b8dc095ffc3e2ac34d
  48. DrahtBot removed the label Needs rebase on May 19, 2021
  49. laanwj commented at 6:47 pm on May 20, 2021: member
    Code review and lightly tested ACK ce6bca88e8c685c69686e0b8dc095ffc3e2ac34d
  50. laanwj merged this on May 20, 2021
  51. laanwj closed this on May 20, 2021

  52. jarolrod commented at 6:55 pm on May 20, 2021: member
    post-merge ACK 👍
  53. jonatack deleted the branch on May 20, 2021
  54. in src/addrman.cpp:509 in ce6bca88e8
    503@@ -501,8 +504,14 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
    504         assert(mapInfo.count(vRandom[n]) == 1);
    505 
    506         const CAddrInfo& ai = mapInfo[vRandom[n]];
    507-        if (!ai.IsTerrible())
    508-            vAddr.push_back(ai);
    509+
    510+        // Filter by network (optional)
    511+        if (network != std::nullopt && ai.GetNetClass() != network) continue;
    


    sipa commented at 7:59 pm on May 20, 2021:

    Won’t this result in infnite loops, if there are not enough of the requested net class? I think doing this correctly requires keeping track of the counts per network.

    EDIT: nevermind, it’s bounded by the size of vRandom as pointed out below.


    jonatack commented at 8:13 pm on May 20, 2021:
    If the early exit isn’t triggered (e.g. getnodeaddresses 10000 i2p) the loop terminates after it has iterated through vRandom.

    vasild commented at 8:09 am on May 21, 2021:
    Today’s computers are so fast that even the infinite loop finishes in about 6 seconds.

    jonatack commented at 8:14 am on May 21, 2021:
    (I think the added functional tests here cover it.)
  55. sidhujag referenced this in commit 4976e3d132 on May 21, 2021
  56. luke-jr referenced this in commit 772600a395 on Jun 27, 2021
  57. luke-jr referenced this in commit dd00626785 on Jun 27, 2021
  58. luke-jr referenced this in commit c752ed5502 on Jun 27, 2021
  59. luke-jr referenced this in commit a21a585b0c on Jun 27, 2021
  60. luke-jr referenced this in commit 5c58d05e45 on Jun 27, 2021
  61. random-zebra referenced this in commit 69979ce40b on Aug 12, 2021
  62. Fabcien referenced this in commit b2a0cf9bd2 on Mar 3, 2022
  63. Fabcien referenced this in commit 368d0c4d1d on Mar 3, 2022
  64. gwillen referenced this in commit bae18ea9ed on Jun 1, 2022
  65. DrahtBot locked this on Aug 18, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-19 00:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me