refactor: Introduce EvictionManager and use it for the inbound eviction logic #25572

pull dergoegge wants to merge 11 commits into bitcoin:master from dergoegge:2022-07-evictionman-2ofN changing 22 files +768 −183
  1. dergoegge commented at 4:39 pm on July 8, 2022: member

    This PR splits off the next couple commits from #25268 that introduce the EvictionManager and use it for the inbound eviction logic.

    One instance of the EvictionManager is created at start up and passed as a reference to the connection and peer managers. The connection and peer managers report all eviction relevant information (for inbound connections) to the eviction manager who ultimately suggests nodes to evict as the result of EvictionManager::SelectNodeToEvict.

  2. fanquake added the label P2P on Jul 8, 2022
  3. fanquake added the label Refactoring on Jul 8, 2022
  4. in src/node/eviction.cpp:255 in 964c048e03 outdated
    250+                                       bool noban, ConnectionType conn_type)
    251+{
    252+    LOCK(m_candidates_mutex);
    253+    // The default values used to initialise the eviction candidates result in
    254+    // newer candidates being more likely to be evicted.
    255+    NodeEvictionCandidate candidate{
    


    theuni commented at 7:31 pm on July 8, 2022:

    I wonder if it might make sense to split NodeEvictionCandidate into 2 parts: the const properties that don’t change (like conn_type/noban) and the non-const state that’s intended to be/might be updated?

    Maybe something like:

     0class NodeEvictionCandidate {
     1  class Properties {
     2    NodeId m_id;
     3    ConnectionType m_conn_type;
     4    bool m_noban;
     5    ...
     6  };
     7  NodeEvictionCandidate(NodeProperties properties) : m_properties(properties){}
     8private:
     9  const NodeProperties m_properties;
    10  bool m_relay_txs;
    11  bool fBloomFilter;
    12  ...
    13};
    14...
    15void EvictionManagerImpl::AddCandidate(NodeEvictionCandidate::Properties props) {...}
    

    I think that might be more straightforward to use as it’s self-documenting, while also allowing for safe lock-free access to the stuff that can’t change.

    Maybe that’s easier said than done though. Thoughts?


    jnewbery commented at 10:42 am on July 13, 2022:
    Even if you don’t do this, I’d suggest marking the const members const, and group them before the mutable members.

    dergoegge commented at 4:54 pm on July 14, 2022:
    I tried to do this but the src/test/net_peer_eviction_tests.cpp tests sadly rely on no members of NodeEvictionCandidate being const. Would like to leave this for a follow up, since it requires changing those tests quite a bit.

    theuni commented at 4:23 pm on August 26, 2022:

    Hmm, I’d say if the tests rely on non-const values, then the tests need to be reworked somewhat (I assume they’re just re-using existing candidates as opposed to creating new ones for the sake of simplicity). Either that or they’re testing state-changes that aren’t possible.

    Agree that it’s not worth refactoring the tests in this PR, but could you maybe organize the members and add a note to the definition of NodeEvictionCandidate to make the possible state changes clear? I think there are basically 3 types, though I may be oversimplifying:

    • These never change after creation
    • These may change once
    • These may change at any time

    dergoegge commented at 1:37 pm on September 26, 2022:

    I have been looking a bit more at making the const NodeEvictionCandidate members const and it turns out that it is not just a test problem at the moment.

    The eviction logic it self relies on non-constness due to multiple std::sort, vector::erase and std::remove_if calls. Will look at making a separate PR for this.

    In the mean time i will add some comments in this PR like you suggested.

  5. theuni commented at 7:34 pm on July 8, 2022: member

    Concept ACK.

    Added a high-level question about NodeEvictionCandidate to kick things off, will continue with review.

  6. DrahtBot commented at 10:31 pm on July 8, 2022: contributor

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

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK theuni, jnewbery, naumenkogs

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #28222 (Use shared_ptr for CNode inside CConnman by willcl-ark)
    • #28170 (p2p: adaptive connections services flags by furszy)
    • #27912 (net: disconnect inside AttemptToEvictConnection by willcl-ark)
    • #27837 (net: introduce block tracker to retry to download blocks after failure by furszy)
    • #27600 (net: Add new permission forceinbound to evict a random unprotected connection if all slots are otherwise full by pinheadmz)
    • #27509 (Relay own transactions only via short-lived Tor or I2P connections by vasild)
    • #27385 (net, refactor: extract Network and BIP155Network logic to node/network by jonatack)
    • #27213 (p2p: Diversify automatic outbound connections with respect to networks by amitiuttarwar)
    • #26812 (test: add end-to-end tests for CConnman and PeerManager by vasild)
    • #26621 (refactor: Continue moving application data from CNode to Peer by dergoegge)

    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.

  7. in src/bench/peer_eviction.cpp:6 in 2f93a9fc87 outdated
    2@@ -3,6 +3,7 @@
    3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
    4 
    5 #include <bench/bench.h>
    6+#include <node/eviction_impl.h>
    


    jnewbery commented at 9:38 am on July 13, 2022:
    please sort alphabetically :)
  8. in src/net.h:15 in 2f93a9fc87 outdated
    11@@ -12,6 +12,7 @@
    12 #include <node/connection_types.h>
    13 #include <consensus/amount.h>
    14 #include <crypto/siphash.h>
    15+#include <node/eviction.h>
    


    jnewbery commented at 9:39 am on July 13, 2022:
    please sort alphabetically :)
  9. in src/net_processing.h:46 in 2f93a9fc87 outdated
    38@@ -39,7 +39,7 @@ struct CNodeStateStats {
    39 class PeerManager : public CValidationInterface, public NetEventsInterface
    40 {
    41 public:
    42-    static std::unique_ptr<PeerManager> make(CConnman& connman, AddrMan& addrman,
    43+    static std::unique_ptr<PeerManager> make(CConnman& connman, AddrMan& addrman, EvictionManager& evictionman,
    


    jnewbery commented at 9:47 am on July 13, 2022:
    Add #include <node/eviction.h>
  10. in src/node/eviction.h:16 in 2f93a9fc87 outdated
    28-    bool prefer_evict;
    29-    bool m_is_local;
    30-    Network m_network;
    31-    bool m_noban;
    32-    ConnectionType m_conn_type;
    33+class EvictionManagerImpl;
    


    jnewbery commented at 9:52 am on July 13, 2022:
    It’s usual to put forward declarations at the top of the file (see eg addrman.h)
  11. in src/node/eviction.h:67 in 2f93a9fc87 outdated
    75+    void UpdateLoadedBloomFilter(NodeId id, bool bloom_filter_loaded);
    76+
    77+    /** Set the candidates tx relay status to true. */
    78+    void UpdateRelayTxs(NodeId id);
    79 };
    80 
    


    jnewbery commented at 9:53 am on July 13, 2022:
    No need for the additional newline at the end.
  12. in src/node/eviction.h:26 in 2f93a9fc87 outdated
    36+{
    37+private:
    38+    const std::unique_ptr<EvictionManagerImpl> m_impl;
    39+
    40+public:
    41+    explicit EvictionManager();
    


    jnewbery commented at 9:54 am on July 13, 2022:
    No need for the explicit keyword, since this ctor doesn’t take any arguments.
  13. in src/node/context.h:25 in 2f93a9fc87 outdated
    21@@ -22,6 +22,7 @@ class CTxMemPool;
    22 class ChainstateManager;
    23 class NetGroupManager;
    24 class PeerManager;
    25+class EvictionManager;
    


    jnewbery commented at 9:55 am on July 13, 2022:
    Please sort alphabetically.
  14. in src/net.cpp:1100 in 2f93a9fc87 outdated
    1094@@ -1112,6 +1095,11 @@ void CConnman::DisconnectNodes()
    1095             }
    1096         }
    1097     }
    1098+
    1099+    for (NodeId id : disconnected_eviction_candidates) {
    1100+        m_evictionman.RemoveCandidate(id);
    1101+    }
    


    jnewbery commented at 10:00 am on July 13, 2022:
    Is there a reason not to do this in the Delete disconnected nodes loop below?

    theuni commented at 5:37 pm on July 13, 2022:
    It’s a different set of nodes, so different loop. Do you mean to do it in the same scope?

    jnewbery commented at 11:57 am on July 14, 2022:

    I guess I don’t understand why the node can’t be removed from the EvictionManager either:

    • in the loop above, at the point where the node is removed from m_nodes and added to m_nodes_disconnected; or
    • in the loop below, at the point where the node is removed from m_nodes_disconnected.

    Perhaps a code comment could be added to explain why.


    dergoegge commented at 5:08 pm on July 14, 2022:

    Cory originally suggested to it this way to untangle the removal from m_nodes_mutex. (See #25268 (review))

    I think it could make sense to do it in the Delete disconnected nodes loop below which is also independent of m_node_mutex. Another option would be to do it in PeerManagerImpl::FinalizeNode() but that might be weird since we add candidates in net.


    jnewbery commented at 5:55 pm on July 14, 2022:

    Ah, thanks for the explanation.

    I can’t see any reason why this call would have to be done outside the m_nodes_mutex. EvictionManager should never call into net, so there isn’t any chance of a lock inversion. Besides, there are other EvictionManager methods (eg the Get...() methods) which are called while holding m_nodes_mutex.


    dergoegge commented at 2:15 pm on July 27, 2022:
    Moved this back into the loop above.
  15. in src/net.h:554 in 2f93a9fc87 outdated
    553@@ -582,7 +554,6 @@ class CNode
    554     /** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
    


    jnewbery commented at 10:15 am on July 13, 2022:
    0    /** A ping-pong round trip has completed successfully. Update latest ping time. */
    

    In fact, m_last_ping_time may as well be moved into Peer since it’s not used in any net level logic and is only for RPC/GUI stats. Could be done as a follow-up.


    dergoegge commented at 4:48 pm on July 14, 2022:
    Gonna leave this for a follow-up.
  16. in src/net.cpp:2559 in 2f93a9fc87 outdated
    2553@@ -2555,6 +2554,22 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
    2554     for (CNode* pnode : m_nodes) {
    2555         vstats.emplace_back();
    2556         pnode->CopyStats(vstats.back());
    2557+
    2558+        auto min_ping_time{m_evictionman.GetMinPingTime(pnode->GetId())};
    2559+        if (min_ping_time) {
    


    jnewbery commented at 10:22 am on July 13, 2022:

    Can be shortened to

    0        if (auto min_ping_time = m_evictionman.GetMinPingTime(pnode->GetId())) {
    

    if you think that’s better. Same below.


    dergoegge commented at 4:49 pm on July 14, 2022:
    Done.
  17. in src/node/eviction.h:48 in 2f93a9fc87 outdated
    58+
    59+    /** A ping-pong round trip has completed successfully. Update minimum ping time. */
    60+    void UpdateMinPingTime(NodeId id, std::chrono::microseconds ping_time);
    61+    std::optional<std::chrono::microseconds> GetMinPingTime(NodeId id) const;
    62+
    63+    /** A new valid block was received. Update the candidates last block time. */
    


    jnewbery commented at 10:23 am on July 13, 2022:

    Grammar nit:

    0    /** A new valid block was received. Update the candidate's last block time. */
    

    Same below.

  18. in src/node/eviction.h:46 in 2f93a9fc87 outdated
    56+     */
    57+    [[nodiscard]] std::optional<NodeId> SelectNodeToEvict() const;
    58+
    59+    /** A ping-pong round trip has completed successfully. Update minimum ping time. */
    60+    void UpdateMinPingTime(NodeId id, std::chrono::microseconds ping_time);
    61+    std::optional<std::chrono::microseconds> GetMinPingTime(NodeId id) const;
    


    jnewbery commented at 10:28 am on July 13, 2022:
    Once the outbound eviction logic has also been moved into EvictionManager, can these three getters be combined into a single GetEvictionCandidateStats() or similar, since they’ll only be used for reporting stats to the user. If you think that’s a good idea, perhaps add that to the function comment for now.
  19. in src/node/eviction.cpp:301 in 2f93a9fc87 outdated
    288+        }
    289+    }
    290+    return ::SelectNodeToEvict(std::move(candidates));
    291+}
    292+
    293+void EvictionManagerImpl::UpdateMinPingTime(NodeId id, std::chrono::microseconds ping_time)
    


    jnewbery commented at 10:29 am on July 13, 2022:
    /me idly wonders whether these setters can be templated to avoid repetitive boilerplate code

    dergoegge commented at 2:16 pm on July 27, 2022:
    Tried to come up with a cool way of doing this with templates but didn’t end with anything useful.

    ajtowns commented at 3:11 am on April 13, 2023:

    I think something like this would work:

     0class EvictionManagerImpl
     1{
     2    ...
     3    template <typename Fn>
     4    auto CandidateOp(NodeId id, Fn&& fn)
     5    {
     6        LOCK(m_candidates_mutex);
     7        auto it = m_candidates.find(offset);
     8        if (it != m_candidates.end()) {
     9            return fn(it->second);
    10        } else {
    11            // return a dummy value of the right type, including void
    12            return ([]() -> decltype(fn(it->second)) { return {}; })();
    13            // EDIT: maybe nicer to write:
    14            using T = decltype(fn(it->second));
    15            return T();
    16        }
    17    }
    18    ...
    19};
    20
    21void EvictionManager::UpdateLastBlockTime(NodeId id, std::chrono::seconds block_time)
    22{
    23    m_impl->CandidateOp(id, [](NodeEvictionCandidate& nec) {
    24        nec.m_last_block_time = block_time;
    25    });
    26}
    27
    28void EvictionManager::GetLastBlockTime(NodeId id) const
    29{
    30    return m_impl->CandidateOp(id, [](const NodeEvictionCandidate& nec) {
    31        return nec.m_last_block_time;
    32    });
    33}
    
  20. in src/test/net_peer_eviction_tests.cpp:5 in 2f93a9fc87 outdated
    1@@ -2,6 +2,7 @@
    2 // Distributed under the MIT software license, see the accompanying
    3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
    4 
    5+#include <node/eviction_impl.h>
    


    jnewbery commented at 10:32 am on July 13, 2022:
    sort

    jnewbery commented at 10:39 am on July 13, 2022:
    sort
  21. in src/node/eviction_impl.h:36 in 2f93a9fc87 outdated
    31+    Network m_network;
    32+    bool m_noban;
    33+    ConnectionType m_conn_type;
    34+};
    35+
    36+[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates);
    


    jnewbery commented at 10:38 am on July 13, 2022:
    Is there any reason why this and ProtectEvictionCandidatesByRatio() aren’t members of EvictionManagerImpl? I’m not saying they have to be, but I’m interested in the design choice.

    dergoegge commented at 5:24 pm on July 14, 2022:
    This is something that @theuni originally also had on his branch and i just went with the same design. To me this seems good because some of the tests purely test these functions without needing the eviction manager and adding them as members would require more test refactoring.

    jnewbery commented at 5:39 pm on July 14, 2022:

    I think that test refactoring would probably be a good thing, since it would ensure that the unit test is not testing a state that EvictionManager can’t get into in the product code. In general, that seems like a good model - unit tests use the public methods to update the state of the object being tested, but optionally also have access to const test-only methods to peek inside the state of the object if it’s difficult to expose that state in other ways.

    Certainly not required in this PR. Could be done in a follow-up (or not at all).

  22. jnewbery commented at 10:43 am on July 13, 2022: contributor

    Big concept ACK!

    Minor cosmetic comments inline.

  23. DrahtBot added the label Needs rebase on Jul 13, 2022
  24. dergoegge force-pushed on Jul 14, 2022
  25. DrahtBot removed the label Needs rebase on Jul 14, 2022
  26. DrahtBot added the label Needs rebase on Jul 19, 2022
  27. dergoegge force-pushed on Jul 27, 2022
  28. dergoegge commented at 2:25 pm on July 27, 2022: member
    Rebased.
  29. DrahtBot removed the label Needs rebase on Jul 27, 2022
  30. DrahtBot added the label Needs rebase on Aug 3, 2022
  31. dergoegge force-pushed on Aug 3, 2022
  32. DrahtBot removed the label Needs rebase on Aug 3, 2022
  33. theuni commented at 4:26 pm on August 26, 2022: member
    Needs a quick linter fix.
  34. DrahtBot added the label Needs rebase on Aug 26, 2022
  35. dergoegge force-pushed on Sep 8, 2022
  36. DrahtBot removed the label Needs rebase on Sep 8, 2022
  37. dergoegge commented at 5:14 pm on September 9, 2022: member
    This has been rebased (including a small linter fix) and is ready for review again!
  38. in src/node/eviction.cpp:253 in 82eb8d34d5 outdated
    248+                                       uint64_t keyed_net_group, bool prefer_evict,
    249+                                       bool is_local, Network network,
    250+                                       bool noban, ConnectionType conn_type)
    251+{
    252+    LOCK(m_candidates_mutex);
    253+    // The default values used to initialise the eviction candidates result in
    


    naumenkogs commented at 8:00 am on September 12, 2022:
    Why don’t go further and summarize which parameters actually matter? Or just mention why it is so

    dergoegge commented at 5:09 pm on October 18, 2022:
    Added some comments for these values.
  39. naumenkogs commented at 8:17 am on September 12, 2022: member
    Concept ACK, light code review ACK 29c853614ac7ffbd6ab6c009f297f92149843e32. This is a great refactor.
  40. fanquake requested review from theuni on Sep 12, 2022
  41. in src/test/denialofservice_tests.cpp:51 in 535c5040a1 outdated
    44@@ -45,10 +45,19 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
    45 // work.
    46 BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
    47 {
    48-    ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
    49-    // Disable inactivity checks for this test to avoid interference
    50-    connman.SetPeerConnectTimeout(99999s);
    51-    PeerManager& peerman = *m_node.peerman;
    52+    auto evictionman = std::make_unique<EvictionManager>();
    


    theuni commented at 1:57 pm on September 15, 2022:

    Why is this switched away from using m_node? Not that I object, it seems reasonable to me.

    If it’s just because “it’s the only use of m_node.connman in these tests”, maybe break that change out as a separate commit?


    dergoegge commented at 3:18 pm on September 20, 2022:

    You actually had this in your original branch and I just kept it this way but it made sense to me since all the other (dos) tests do it this way as well (i.e. “it’s the only use of m_node.connman in these tests”).

    Added a commit that splits out this change.

  42. DrahtBot added the label Needs rebase on Sep 20, 2022
  43. dergoegge force-pushed on Sep 20, 2022
  44. dergoegge force-pushed on Sep 20, 2022
  45. DrahtBot removed the label Needs rebase on Sep 20, 2022
  46. DrahtBot added the label Needs rebase on Oct 17, 2022
  47. dergoegge force-pushed on Oct 18, 2022
  48. dergoegge commented at 5:08 pm on October 18, 2022: member
    Rebased and added some docs for the initial NodeEvictionCandidate values.
  49. DrahtBot removed the label Needs rebase on Oct 18, 2022
  50. dergoegge force-pushed on Oct 28, 2022
  51. dergoegge force-pushed on Oct 28, 2022
  52. DrahtBot added the label Needs rebase on Nov 2, 2022
  53. dergoegge force-pushed on Nov 26, 2022
  54. dergoegge force-pushed on Nov 28, 2022
  55. DrahtBot removed the label Needs rebase on Nov 28, 2022
  56. dergoegge force-pushed on Nov 28, 2022
  57. dergoegge commented at 9:33 pm on November 28, 2022: member
    Finally got around to adding a fuzz target for the Eviction Manager. The testing oracle is pretty dumb right now, gonna think about how that can be improved… The oracle could also be improved on later.
  58. DrahtBot added the label Needs rebase on Nov 30, 2022
  59. dergoegge force-pushed on Dec 1, 2022
  60. DrahtBot removed the label Needs rebase on Dec 1, 2022
  61. dergoegge force-pushed on Dec 2, 2022
  62. DrahtBot added the label Needs rebase on Mar 11, 2023
  63. dergoegge force-pushed on Mar 15, 2023
  64. DrahtBot removed the label Needs rebase on Mar 15, 2023
  65. DrahtBot added the label Needs rebase on Mar 23, 2023
  66. dergoegge force-pushed on Mar 27, 2023
  67. DrahtBot removed the label Needs rebase on Mar 27, 2023
  68. DrahtBot added the label Needs rebase on Mar 28, 2023
  69. dergoegge force-pushed on Mar 28, 2023
  70. DrahtBot removed the label Needs rebase on Mar 28, 2023
  71. fanquake referenced this in commit 53eb4b7a21 on Apr 11, 2023
  72. DrahtBot added the label Needs rebase on Apr 11, 2023
  73. sidhujag referenced this in commit 4fe31e65c8 on Apr 11, 2023
  74. dergoegge force-pushed on Apr 12, 2023
  75. DrahtBot removed the label Needs rebase on Apr 12, 2023
  76. in src/net_processing.cpp:488 in dccf022242 outdated
    490@@ -490,7 +491,7 @@ struct CNodeState {
    491 class PeerManagerImpl final : public PeerManager
    492 {
    493 public:
    494-    PeerManagerImpl(CConnman& connman, AddrMan& addrman,
    495+    PeerManagerImpl(CConnman& connman, AddrMan& addrman, EvictionManager& evictionman,
    


    ajtowns commented at 2:20 am on April 13, 2023:

    Why not just use the evictionman from connman directly (or have connman use its peerman’s eviction manager)? Is there any reason to ever want them to have different eviction managers?

    Having done that, why not have CConnman (or PeerManager) create (and own) its own eviction manager, rather than needing one to be passed in?


    dergoegge commented at 10:31 am on April 13, 2023:

    I think it makes sense to not have the eviction manager be owned by another component, in the context of also moving the outbound eviction logic to the eviction manager. I see it as more of a standalone component like the addrman or banman.

    This might also give us flexibility in mocking it if we wanted to for testing purposes (e.g. to test that net processing and net are updating the stats correctly, or have a FuzzedEvictionManager to let the fuzzer choose which peers to evict).

  77. in src/node/eviction.cpp:294 in 14f06a2ea5 outdated
    289+std::optional<NodeId> EvictionManagerImpl::SelectNodeToEvict() const
    290+{
    291+    std::vector<NodeEvictionCandidate> candidates;
    292+    {
    293+        LOCK(m_candidates_mutex);
    294+        for (const auto& [id, candidate] : m_candidates) {
    


    ajtowns commented at 2:29 am on April 13, 2023:
    candidates.reserve(m_candidates.size()) ?
  78. in src/net.cpp:2627 in 14f06a2ea5 outdated
    2609+        if (auto last_block_time = m_evictionman.GetLastBlockTime(pnode->GetId())) {
    2610+            vstats.back().m_last_block_time = *last_block_time;
    2611+        }
    2612+
    2613+        if (auto last_tx_time = m_evictionman.GetLastTxTime(pnode->GetId())) {
    2614+            vstats.back().m_last_tx_time = *last_tx_time;
    


    ajtowns commented at 3:24 am on April 13, 2023:
    m_evictionman.CopyEvictionStats(pnode->GetId(), vstats.back()); ?

    dergoegge commented at 10:43 am on April 13, 2023:
    Yea something like that would make sense. Also similar to John’s comment.
  79. in src/net_processing.cpp:5115 in 14f06a2ea5 outdated
    5014@@ -5008,7 +5015,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
    5015             if (pnode->GetId() > youngest_peer.first) {
    5016                 next_youngest_peer = youngest_peer;
    5017                 youngest_peer.first = pnode->GetId();
    5018-                youngest_peer.second = pnode->m_last_block_time;
    5019+                youngest_peer.second = *Assert(m_evictionman.GetLastBlockTime(pnode->GetId()));
    


    ajtowns commented at 3:27 am on April 13, 2023:
    Repeatedly looking up the eviction manager map and locking and unlocking access to it, and introducing the potential for maps to be out of sync and having to add asserts to check for that doesn’t seem ideal…

    dergoegge commented at 9:41 am on April 13, 2023:

    Repeatedly looking up the eviction manager map and locking and unlocking access to it

    Two things:

    • There are very few full outbound or block relay only connections, so this happens at most maybe 3 or 4 times for the block relay only loop and 11 or 12 times for the full outbound one.
    • The outbound eviction logic is also moved to the eviction manager in a follow up (see #25268), which removes this repeated locking.

    and introducing the potential for maps to be out of sync and having to add asserts to check for that doesn’t seem ideal…

    I don’t remember what I was thinking at the time but now this Assert doesn’t seem great to me either. I think this is safe because ForEachNode locks m_nodes_mutex and only iterates over nodes that completed the version handshake but that is quite the spaghetti assumption.

    Simply using the default value for the last block time if the eviction manager doesn’t know about this peer would probably be the right thing to do. And then without the assertions, I wouldn’t be concerned about the maps (assuming your are talking about the peer map and the eviction manager map) being out of sync.

    (This also resolves itself if we end up moving the outbound eviction logic to the eviction manager as well, because then there is only one internal eviction map to think about)

  80. dergoegge commented at 10:50 am on April 13, 2023: member
    @ajtowns Thank you for the comments!
  81. in src/net.cpp:910 in d0e7bb90a2 outdated
    923-                .m_conn_type = node->m_conn_type,
    924-            };
    925-            vEvictionCandidates.push_back(candidate);
    926+
    927+            auto eviction_candidate{m_evictionman.GetCandidate(node->GetId())};
    928+            assert(eviction_candidate);
    


    mzumsande commented at 4:46 pm on April 13, 2023:
    Could use Assume and continue in order to avoid the assert.
  82. in src/net.h:408 in 00230350cd outdated
    403@@ -404,7 +404,6 @@ class CNode
    404      * from the wire. This cleaned string can safely be logged or displayed.
    405      */
    406     std::string cleanSubVer GUARDED_BY(m_subver_mutex){};
    407-    const bool m_prefer_evict{false}; // This peer is preferred for eviction.
    


    mzumsande commented at 4:49 pm on April 13, 2023:
    00230350cd32d5a1d2421b588a7f493afa7c69dd: I think that prefer_evict could also be removed from CNodeOptions.
  83. in src/net.cpp:906 in f233b005ec outdated
    894@@ -895,20 +895,7 @@ size_t CConnman::SocketSendData(CNode& node) const
    895  */
    896 bool CConnman::AttemptToEvictConnection()
    897 {
    898-    std::vector<NodeEvictionCandidate> vEvictionCandidates;
    899-    {
    900-        LOCK(m_nodes_mutex);
    901-        for (const CNode* node : m_nodes) {
    902-            if (node->fDisconnect)
    


    mzumsande commented at 5:01 pm on April 13, 2023:
    This removes the check node->fDisconnect, which I think could be dangerous: We set fDisconnect in AttemptToEvictConnection(), but don’t immediately disconnect. The actual cleanup happens at some later point, when ThreadSocketHandler calls DisconnectNodes(). So if we have an attacker that makes new connections to us rapidly, there would be a race between ThreadSocketHandler and the attacker making the next connection to us. If the attacker wins this race, we could accept two inbound connections, but, without the check that is being removed here, AttemptToEvictConnection() could mark the same inbound peer for eviction twice, so that we’ll actually only evict one peer. Since inbound eviction is triggered only in CreateNodeFromAcceptedSocket() (and not through some regularly scheduled job), this could lead to us having an extra inbound peer above our limit indefinitely. Now if the attacker repeats this scheme many times, they could make thousands of inbound connections to us / exhaust our resources / crash our node.

    mzumsande commented at 11:51 pm on April 17, 2023:
    hmm, thinking more about this, I didn’t see the whole picture, because everything happens in ThreadSocketHandler - after CConnman::SocketHandler() -> CConnman::SocketHandlerListening(), CConnman::DisconnectNodes() is called, so it’s not possible to accept new connections in between - however, CConnman::SocketHandlerListening() calls AcceptConnection() in a loop for multiple ListenSockets, so if we have multiple listening sockets and an attacker would connect to more than one at the same time, the scenario above may still be possible?
  84. DrahtBot added the label Needs rebase on Apr 20, 2023
  85. dergoegge force-pushed on Apr 21, 2023
  86. dergoegge commented at 9:20 am on April 21, 2023: member
    Rebased, have not addressed Martin’s comments yet
  87. DrahtBot removed the label Needs rebase on Apr 21, 2023
  88. DrahtBot added the label Needs rebase on May 10, 2023
  89. dergoegge force-pushed on May 30, 2023
  90. DrahtBot removed the label Needs rebase on May 30, 2023
  91. DrahtBot added the label CI failed on May 30, 2023
  92. DrahtBot removed the label CI failed on May 31, 2023
  93. DrahtBot added the label CI failed on Jul 15, 2023
  94. MarcoFalke commented at 8:43 am on July 21, 2023: member
    Needs rebase if still relevant
  95. dergoegge force-pushed on Jul 24, 2023
  96. DrahtBot added the label Needs rebase on Jul 25, 2023
  97. [test] Make all denial of service tests use their own connman/peerman e86cd1f977
  98. dergoegge force-pushed on Jul 26, 2023
  99. [eviction] Create EvictionManager stub 981617d338
  100. [eviction] Make EvictionManager keep track of candidates 6de4364e8e
  101. [net] Get candidates from eviction manager
    We temporarily introduce a method to get a specific
    NodeEvictionCandidate from the eviction manager for use in
    `CConnman::AttemptToEvictConnection()`. `EvictionManager::GetCandidate`
    is removed once we are done moving the remaining eviction state from
    `CNode` to the eviction manager.
    bc7e7fc60a
  102. [net] Remove unused CNode state
    Now that the eviction manager is aware of the keyed net group and
    whether or not a peer is prefered for eviction, we can get rid of the
    corresponding CNode members, since they are not used elsewhere.
    7f7d02cdb6
  103. [eviction] Move ping/block/tx times from CNode to EvictionManager 157afa0b00
  104. [eviction] Report services to EvictionManager 5a3ecac7c0
  105. [eviction] Move BIP37 tx relay and bloom filter status to EvictionManager 98d484706e
  106. [eviction] Move SelectNodeToEvict into EvictionManager 3bdaabd27d
  107. [doc] Document relevant initial NodeEvictionCandidate values 6b53d0a2f5
  108. [fuzz] Add EvictionManager target 2977ca3780
  109. dergoegge force-pushed on Jul 26, 2023
  110. DrahtBot removed the label Needs rebase on Jul 26, 2023
  111. DrahtBot removed the label CI failed on Jul 26, 2023
  112. DrahtBot added the label Needs rebase on Aug 6, 2023
  113. DrahtBot commented at 5:48 pm on August 6, 2023: contributor

    🐙 This pull request conflicts with the target branch and needs rebase.

  114. achow101 marked this as a draft on Sep 20, 2023
  115. fanquake commented at 1:57 pm on September 21, 2023: member
  116. dergoegge closed this on Sep 28, 2023


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-07-01 10:13 UTC

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