p2p: return CSubNet in LookupSubNet #26078

pull brunoerg wants to merge 1 commits into bitcoin:master from brunoerg:2022-09-csubnet-lookup changing 8 files +101 −115
  1. brunoerg commented at 9:25 pm on September 13, 2022: contributor

    Analyzing the usage of LookupSubNet, noticed that most cases uses check if the subnet is valid by calling subnet.IsValid(), and the boolean returned by LookupSubNet hasn’t been used so much, see: https://github.com/bitcoin/bitcoin/blob/29d540b7ada890dd588c4825d40c27c5e6f20061/src/httpserver.cpp#L172-L174 https://github.com/bitcoin/bitcoin/blob/29d540b7ada890dd588c4825d40c27c5e6f20061/src/net_permissions.cpp#L114-L116

    It makes sense to return CSubNet instead of bool.

  2. DrahtBot added the label P2P on Sep 13, 2022
  3. w0xlt commented at 11:23 pm on September 13, 2022: contributor
    Approach ACK
  4. jonatack commented at 11:17 am on September 14, 2022: member

    Interesting simplification and looks reasonable at first glance. A possible alternative would be to retain the checks and make LookupSubNet return std::optional<CSubNet> instead.

    0rpc/net.cpp:717:9: error: no matching function for call to 'LookupSubNet'
    1        LookupSubNet(request.params[0].get_str(), subNet);
    2        ^~~~~~~~~~~~
    3./netbase.h:177:9: note: candidate function not viable: requires single argument 'subnet_str', but 2 arguments were provided
    4CSubNet LookupSubNet(const std::string& subnet_str);
    5        ^
    61 error generated.
    
  5. in src/netbase.h:175 in 3007397adc outdated
    171@@ -172,11 +172,9 @@ CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLoo
    172  * @param[in]  subnet_str  A string representation of a subnet of the form
    173  *                         `network address [ "/", ( CIDR-style suffix | netmask ) ]`
    174  *                         e.g. "2001:db8::/32", "192.0.2.0/255.255.255.0" or "8.8.8.8".
    175- * @param[out] subnet_out  Internal subnet representation, if parsable/resolvable
    176- *                         from `subnet_str`.
    177- * @returns whether the operation succeeded or not.
    178+ * @returns CSubNet object.
    


    jonatack commented at 11:20 am on September 14, 2022:

    Perhaps mention possible non-valid result here

    0 * [@returns](/bitcoin-bitcoin/contributor/returns/) a CSubNet object (that may or may not be valid).
    

    brunoerg commented at 1:57 pm on September 14, 2022:
    Yes, make sense. Addressed it on latest push.
  6. brunoerg force-pushed on Sep 14, 2022
  7. brunoerg marked this as ready for review on Sep 14, 2022
  8. brunoerg force-pushed on Sep 14, 2022
  9. brunoerg marked this as a draft on Sep 14, 2022
  10. DrahtBot commented at 10:44 pm on September 14, 2022: contributor

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

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK vasild, theStack, achow101
    Concept ACK stickies-v
    Stale ACK w0xlt

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    No conflicts as of last run.

  11. brunoerg force-pushed on Sep 16, 2022
  12. brunoerg force-pushed on Sep 16, 2022
  13. brunoerg force-pushed on Sep 19, 2022
  14. brunoerg marked this as ready for review on Sep 19, 2022
  15. brunoerg commented at 5:43 pm on September 19, 2022: contributor
    Addressed @jonatack’s review and now it returns std::optional<CSubNet>.
  16. in src/test/fuzz/netbase_dns_lookup.cpp:68 in 0b3db2f581 outdated
    62@@ -63,9 +63,9 @@ FUZZ_TARGET(netbase_dns_lookup)
    63         assert(!resolved_service.IsInternal());
    64     }
    65     {
    66-        CSubNet resolved_subnet;
    67-        if (LookupSubNet(name, resolved_subnet)) {
    68-            assert(resolved_subnet.IsValid());
    69+        std::optional<CSubNet> resolved_subnet = LookupSubNet(name);
    70+        if (resolved_subnet.has_value()) {
    71+            assert(resolved_subnet.value().IsValid() || !resolved_subnet.value().IsValid());
    


    mzumsande commented at 9:01 pm on September 19, 2022:
    This assert looks tautological. More general, if LookupSubNet is changed to return an optional, would it be possible to either return a valid CSubNet, or std::nullopt? Or is there a need to distinguish between std::nullopt and an invalid but existing CSubNet?

    brunoerg commented at 1:43 pm on September 20, 2022:
    You’re right, there is no need to return an invalid but existingCSubNet. Just changed the approach to return only a valid one otherwise it returns std::nullopt.
  17. luke-jr commented at 11:56 pm on September 19, 2022: member
    std::optional seems redundant here. I think it’s better to just return the CSubNet?
  18. in src/netbase.cpp:701 in 0b3db2f581 outdated
    697@@ -698,23 +698,20 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
    698             uint8_t netmask;
    699             if (ParseUInt8(netmask_str, &netmask)) {
    700                 // Valid number; assume CIDR variable-length subnet masking.
    701-                subnet_out = CSubNet{addr, netmask};
    702-                return subnet_out.IsValid();
    703+                return CSubNet{addr, netmask};
    


    luke-jr commented at 0:01 am on September 20, 2022:
    Returning a non-nullopt invalid subnet here and elsewhere is liable to introduce bugs

    brunoerg commented at 1:41 pm on September 20, 2022:
    I agree, force-pushed fixing it.
  19. brunoerg force-pushed on Sep 20, 2022
  20. brunoerg commented at 1:45 pm on September 20, 2022: contributor
    Force-pushed to make LookupSubnet not return an invalid but existing CSubNet, now it returns a valid CSubNet or std::nullopt. Thanks, @luke-jr and @mzumsande.
  21. w0xlt approved
  22. luke-jr commented at 2:23 pm on September 20, 2022: member
    I still think adding a std::optional here is asking for bugs. We’re already seeing this kind of thing with the new util::Result stuff. It’s important to only have one “no value” state.
  23. brunoerg force-pushed on Sep 20, 2022
  24. w0xlt commented at 12:50 pm on September 21, 2022: contributor

    I don´t think std::optional is a problem per se, but CSubNet has the bool CSubNet::valid which can be used instead of std::optional in this case.

    The problem in util::Result has more to do with the complexity of the class than in the use of std::optional.

  25. luke-jr commented at 3:12 am on September 22, 2022: member
    The problem is having two ways to represent an invalid state, especially when they can be at odds with each other (in that case, .has_value() && !->IsValid()).
  26. brunoerg commented at 12:35 pm on September 22, 2022: contributor

    The problem is having two ways to represent an invalid state, especially when they can be at odds with each other (in that case, .has_value() && !->IsValid()).

    Fair enough, it’s better to return CSubNet instead. I’m going to change it.

  27. brunoerg force-pushed on Sep 22, 2022
  28. w0xlt approved
  29. w0xlt commented at 2:38 pm on September 22, 2022: contributor

    reACK https://github.com/bitcoin/bitcoin/pull/26078/commits/fc60ced518c7d5e1696018e1378c457b70c6909b

    nit: Maybe an explicit initialization could be added?

    0class CSubNet
    1{
    2protected:
    3    // ...
    4    /// Is this value valid? (only used to signal parse errors)
    5    bool valid{false};
    
  30. in src/httpserver.cpp:172 in fc60ced518 outdated
    168@@ -169,8 +169,7 @@ static bool InitHTTPAllowList()
    169     rpc_allow_subnets.push_back(CSubNet(localv4, 8));      // always allow IPv4 local subnet
    170     rpc_allow_subnets.push_back(CSubNet(localv6));         // always allow IPv6 localhost
    171     for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
    172-        CSubNet subnet;
    173-        LookupSubNet(strAllow, subnet);
    174+        CSubNet subnet = LookupSubNet(strAllow);
    


    vasild commented at 12:02 pm on February 17, 2023:

    nit, here and elsewhere:

    0        const CSubNet subnet = LookupSubNet(strAllow);
    

    brunoerg commented at 6:22 pm on February 17, 2023:
    Done
  31. in src/netbase.cpp:663 in fc60ced518 outdated
    686+CSubNet LookupSubNet(const std::string& subnet_str)
    687 {
    688+    CSubNet subnet;
    689     if (!ContainsNoNUL(subnet_str)) {
    690-        return false;
    691+        return subnet;
    


    vasild commented at 12:08 pm on February 17, 2023:
    nit: maybe add assert(!subnet.IsValid()); after CSubNet subnet; to make it obvious that we return an invalid object and to guard against future changes that construct a valid CSubNet by default.

    brunoerg commented at 6:22 pm on February 17, 2023:
    Make sense, done!
  32. in src/qt/rpcconsole.cpp:1312 in fc60ced518 outdated
    1312-
    1313-        LookupSubNet(strNode.toStdString(), possibleSubnet);
    1314-        if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet))
    1315-        {
    1316+        std::optional<CSubNet> possibleSubnet = LookupSubNet(strNode.toStdString());
    1317+        if (possibleSubnet.has_value() && m_node.unban(possibleSubnet.value())) {
    


    vasild commented at 12:11 pm on February 17, 2023:
    Hmm, possibleSubnet.has_value() will always be true. I guess this is an artifact from a previous incarnation of this PR that used std::optional.

    brunoerg commented at 3:14 pm on February 17, 2023:
    Yea, nice find, thanks!
  33. in src/test/fuzz/netbase_dns_lookup.cpp:67 in fc60ced518 outdated
    62@@ -63,9 +63,7 @@ FUZZ_TARGET(netbase_dns_lookup)
    63         assert(!resolved_service.IsInternal());
    64     }
    65     {
    66-        CSubNet resolved_subnet;
    67-        if (LookupSubNet(name, resolved_subnet)) {
    68-            assert(resolved_subnet.IsValid());
    69-        }
    70+        CSubNet resolved_subnet = LookupSubNet(name);
    71+        assert(resolved_subnet.IsValid() || !resolved_subnet.IsValid());
    


    vasild commented at 12:39 pm on February 17, 2023:
    x || !x will never be false. It suffices to change this to (void)LookupSubNet(name);.

    brunoerg commented at 6:23 pm on February 17, 2023:
    Done!
  34. in src/test/netbase_tests.cpp:28 in fc60ced518 outdated
    30@@ -31,9 +31,7 @@ static CNetAddr ResolveIP(const std::string& ip)
    31 
    32 static CSubNet ResolveSubNet(const std::string& subnet)
    33 {
    34-    CSubNet ret;
    35-    LookupSubNet(subnet, ret);
    36-    return ret;
    37+    return LookupSubNet(subnet);
    38 }
    


    vasild commented at 12:41 pm on February 17, 2023:
    Now ResolveSubNet() is identical to LookupSubNet(). Maybe ditch the former and change the callers to use directly LookupSubNet()?

    brunoerg commented at 6:21 pm on February 17, 2023:
    Yes, better to call LookupSubNet().
  35. vasild changes_requested
  36. brunoerg force-pushed on Feb 17, 2023
  37. brunoerg commented at 6:24 pm on February 17, 2023: contributor
    Force-pushed addressing @vasild’s review.
  38. in src/qt/rpcconsole.cpp:1316 in 2f5a5cc0aa outdated
    1316-
    1317-        LookupSubNet(strNode.toStdString(), possibleSubnet);
    1318-        if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet))
    1319-        {
    1320+        const CSubNet possibleSubnet{LookupSubNet(strNode.toStdString())};
    1321+        if (m_node.unban(possibleSubnet)) {
    


    vasild commented at 2:15 pm on February 20, 2023:

    The new code could call unban() with an invalid subnet whereas the previous one would not. unban() would call m_banned.erase() which would use operator==(const CSubNet& a, const CSubNet& b) which could match another invalid entry, I guess. Maybe that is ok, but to keep this change “non-functional”, the new code should be:

    0if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet)) {
    

    brunoerg commented at 10:00 pm on February 20, 2023:
    Makes sense! Gonna address it!
  39. vasild commented at 2:16 pm on February 20, 2023: contributor
    Almost ACK 2f5a5cc0aaad1cf0fdda5d1ceaafcde9253264c7
  40. DrahtBot requested review from w0xlt on Feb 20, 2023
  41. brunoerg force-pushed on Feb 20, 2023
  42. brunoerg commented at 10:38 pm on February 20, 2023: contributor
    Force-pushed addressing lastest @vasild’s review
  43. vasild approved
  44. vasild commented at 2:35 pm on February 21, 2023: contributor

    ACK 9fb86661cf81e27131eb5f8d901397a25e2cd4b4

    Thanks!

  45. DrahtBot added the label Needs rebase on Mar 9, 2023
  46. brunoerg force-pushed on Mar 9, 2023
  47. brunoerg commented at 2:47 pm on March 9, 2023: contributor
    Rebased
  48. DrahtBot removed the label Needs rebase on Mar 9, 2023
  49. vasild approved
  50. vasild commented at 12:32 pm on March 16, 2023: contributor
    ACK 4e377d8b684218d49229babc5959e07f38793549
  51. DrahtBot removed review request from w0xlt on Mar 16, 2023
  52. DrahtBot requested review from w0xlt on Mar 16, 2023
  53. DrahtBot added the label CI failed on May 30, 2023
  54. achow101 referenced this in commit 71300489af on May 30, 2023
  55. DrahtBot added the label Needs rebase on May 30, 2023
  56. sidhujag referenced this in commit e0f2a7bc41 on May 30, 2023
  57. p2p: return `CSubNet` in `LookupSubNet` fb3e812277
  58. brunoerg force-pushed on May 30, 2023
  59. DrahtBot removed the label Needs rebase on May 30, 2023
  60. DrahtBot removed the label CI failed on May 31, 2023
  61. vasild approved
  62. vasild commented at 7:36 am on June 8, 2023: contributor
    ACK fb3e812277041f239b97b88689a5076796d75b9b
  63. DrahtBot removed review request from w0xlt on Jun 8, 2023
  64. DrahtBot requested review from w0xlt on Jun 8, 2023
  65. achow101 removed review request from w0xlt on Sep 20, 2023
  66. achow101 requested review from theStack on Sep 20, 2023
  67. achow101 requested review from stickies-v on Sep 20, 2023
  68. theStack approved
  69. theStack commented at 0:30 am on October 3, 2023: contributor
    Code-review ACK fb3e812277041f239b97b88689a5076796d75b9b
  70. DrahtBot requested review from w0xlt on Oct 3, 2023
  71. in src/test/netbase_tests.cpp:244 in fb3e812277
    239@@ -247,85 +240,85 @@ BOOST_AUTO_TEST_CASE(subnet_test)
    240     BOOST_CHECK(!CSubNet(tor_addr, 200).IsValid());
    241     BOOST_CHECK(!CSubNet(tor_addr, ResolveIP("255.0.0.0")).IsValid());
    242 
    243-    subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
    244+    subnet = LookupSubNet("1.2.3.4/255.255.255.255");
    245     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
    


    stickies-v commented at 3:50 pm on October 9, 2023:
    nit: would make sense to make these one-liners, I think, ideally w/ scripted diff? Or a fn/lambda CheckSubnetEquals to make it even more readable?
  72. stickies-v commented at 4:14 pm on October 9, 2023: contributor

    Concept ACK, but Approach ~0 (for now). Reviewed the code (fb3e812277041f239b97b88689a5076796d75b9b) and it all looks good to me.

    Generally supportive of reducing out-parameters in our function signatures, and this PR offers a modest improvement in readability and uniformizes how we check the return value of LookupSubNet, which is nice.

    I think luke-jr raised a good point that having the return value be falsy in two different ways (through std::optional wrapper and .IsValid() is dangerous and should be avoided, and I agree. I’m approach ~0 as I think this PR improves things, but I think (but did not yet fully implement/verify) the real improvement would be to enforce CSubNet validity in the constructor (wrapped with std::optional factory methods) so we can improve the interface by handling bad input data early and guarantee that all CSubNet instances are valid, and wrap them in a std::optional when validity is not guaranteed. This requires a more substantial refactoring, though, so I’m not opposed to merging this first (and my suggested approach may turn out infeasible/not worth it in practice) - but I think it would make for a much cleaner interface.

  73. DrahtBot removed review request from w0xlt on Oct 9, 2023
  74. DrahtBot requested review from w0xlt on Oct 9, 2023
  75. DrahtBot removed review request from w0xlt on Oct 9, 2023
  76. DrahtBot requested review from w0xlt on Oct 9, 2023
  77. DrahtBot removed review request from w0xlt on Oct 9, 2023
  78. DrahtBot requested review from w0xlt on Oct 9, 2023
  79. achow101 commented at 6:21 pm on October 26, 2023: member
    ACK fb3e812277041f239b97b88689a5076796d75b9b
  80. DrahtBot removed review request from w0xlt on Oct 26, 2023
  81. DrahtBot requested review from w0xlt on Oct 26, 2023
  82. DrahtBot requested review from stickies-v on Oct 26, 2023
  83. achow101 merged this on Oct 26, 2023
  84. achow101 closed this on Oct 26, 2023

  85. achow101 removed review request from w0xlt on Oct 26, 2023
  86. achow101 removed review request from stickies-v on Oct 26, 2023
  87. bitcoin locked this on Oct 25, 2024

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-11-24 15:12 UTC

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