net: Reduce local network activity when networkactive=0 #34486

pull willcl-ark wants to merge 5 commits into bitcoin:master from willcl-ark:respect-networkactive changing 12 files +227 −10
  1. willcl-ark commented at 5:46 PM on February 2, 2026: member

    Fixes #34190

    When networkactive=0 is set, NAT-PMP port mapping and Tor control connections still run in the background, mapping ports and logging retry attempts despite the node being "inactive."

    This wires both subsystems to CConnman::SetNetworkActive so they start and stop with the network state:

    • mapport: EnableMapPort is injected as a callback via CConnman::Options. SetNetworkActive and SetMapPortEnabled both gate on network state.

    • torcontrol: TorController is injected similarly through a CConnman::Options callback. The controller thread stays alive while networkactive=0, but idles without connecting or reconnecting to the Tor control port. Re-enabling the network wakes the controller promptly and resets reconnect backoff.

  2. DrahtBot added the label P2P on Feb 2, 2026
  3. willcl-ark commented at 5:47 PM on February 2, 2026: member

    This is an alternative to #34467. The key difference is that #34467 gates mapport and tor control at init time with if (networkactive) guards, which means those subsystems are permanently disabled for the lifetime of the process. setnetworkactive true via RPC won't start them. Boot-time and runtime behavior would now differ.

    This PR instead wires both subsystems into CConnman::SetNetworkActive so they follow the network state through the full lifecycle: starting with -networkactive=0 and later calling setnetworkactive true works as expected.

    I'm unsure how this will conflict with the work currently being done to remove libevent.

  4. DrahtBot commented at 5:47 PM on February 2, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34486.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK sedited, fanquake, Jhackman2019, brunoerg

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35292 (test: Add coverage for Tor control HASHEDPASSWORD authentication by winterrdog)
    • #35252 (net: send decoy transactions via private broadcast by andrewtoth)
    • #34892 (net: Warn when Tor onion service lacks a dedicated onion bind by HouseOfHufflepuff)
    • #34534 (rpc: Manual prune lock management (Take 2) by fjahr)
    • #34213 (net: preserve anchors when network is disabled by brunoerg)
    • #31260 (scripted-diff: Type-safe settings retrieval by ryanofsky)
    • #30951 (net: option to disallow v1 connection on ipv4 and ipv6 peers by stratospher)

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  5. sedited commented at 5:50 PM on February 2, 2026: contributor

    Concept ACK

  6. bradleystachurski commented at 9:42 PM on February 2, 2026: none

    Reviewed 35da4e03b18b7ef5eb23e1b038f5755fe37825a1

    Tested on Linux: started with -networkactive=0 -natpmp=1 -debug=net -debug=tor, confirmed no portmap/tor activity at startup, toggled via setnetworkactive, confirmed mapport thread start/stop and tor connection attempts follow network state.

    Verified feature_mapport.py fails when the m_mapport callback is removed from SetNetworkActive.

    nit: TorController::SetNetworkActive doesn't reset reconnect_timeout, so re-enabling network after backoff has grown continues from the stale value. Verified this fixes it:

    diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
    index d5aeb55a72..934499d72b 100644
    --- a/src/torcontrol.cpp
    +++ b/src/torcontrol.cpp
    @@ -677,6 +677,8 @@ void TorController::SetNetworkActive(bool set_active)
             // Disconnect if currently connected
             conn.Disconnect();
         }
    +    // Reset backoff when re-enabling network
    +    reconnect_timeout = RECONNECT_TIMEOUT_START;
         // Connect handles both cases: connects if active, reschedules if inactive
         Connect();
     }
    
  7. willcl-ark force-pushed on Feb 3, 2026
  8. willcl-ark commented at 9:28 AM on February 3, 2026: member

    Thanks @bradleystachurski that's a nice suggestion which I've taken in 745aed37224102888332823aadc6d766e701aa0b

    I also reworked the if logic slightly to make the flow of this function clearer (and not always call Connect()).

  9. fanquake commented at 10:10 AM on February 3, 2026: member

    Concept ACK

  10. willcl-ark commented at 10:25 AM on February 3, 2026: member

    I will address the LLM linter suggestion if I push again.

  11. Jhackman2019 commented at 3:37 AM on February 7, 2026: none

    Tested this on my Pi 5 (ARM64, Debian Bookworm). Builds clean, all the networking-related tests pass:

    feature_mapport.py                  PASSED
    feature_proxy.py                    PASSED
    p2p_addr_relay.py                   PASSED
    p2p_disconnect_ban.py --v1transport PASSED
    p2p_disconnect_ban.py --v2transport PASSED
    p2p_dns_seeds.py                    PASSED
    

    Had to clear my test/cache first since I had a stale cache from an autotools build — after that everything was smooth.

    Concept ACK

  12. brunoerg commented at 1:47 PM on February 17, 2026: contributor

    Concept ACK

  13. brunoerg commented at 5:10 PM on February 17, 2026: contributor

    tested up to 396b56af0ac261863b076ab8d2d02a99f6e03f3a: I checked that portmap activity follows network activity.

  14. in src/torcontrol.cpp:639 in 745aed3722 outdated
     635 | @@ -640,6 +636,11 @@ void TorController::disconnected_cb(TorControlConnection& _conn)
     636 |      if (!reconnect)
     637 |          return;
     638 |  
     639 | +    if (!m_network_active) {
    


    brunoerg commented at 5:18 PM on February 17, 2026:

    Is there any way to test this condition? I've tried several scenarios manually, but haven't been able to achieve it.

    However, checking that it is not connected to any Tor control port and then will retry was easier, could also check it on a functional test, e.g:

    diff --git a/test/functional/p2p_private_broadcast.py b/test/functional/p2p_private_broadcast.py
    index 4943841790..b163020e85 100755
    --- a/test/functional/p2p_private_broadcast.py
    +++ b/test/functional/p2p_private_broadcast.py
    @@ -433,9 +433,11 @@ class P2PPrivateBroadcast(BitcoinTestFramework):
                 # the RPC should throw.
                 "-torcontrol=127.0.0.1:1",
                 "-listenonion",
    +            "-debug=tor",
             ])
    -        assert_raises_rpc_error(-1, "none of the Tor or I2P networks is reachable",
    -                                tx_originator.sendrawtransaction, hexstring=txs[0]["hex"], maxfeerate=0.1)
    +        with tx_originator.assert_debug_log(['Not connected to Tor control port'], timeout=5):
    +            assert_raises_rpc_error(-1, "none of the Tor or I2P networks is reachable",
    +                                    tx_originator.sendrawtransaction, hexstring=txs[0]["hex"], maxfeerate=0.1)
    
    
    

    willcl-ark commented at 4:20 PM on February 19, 2026:

    Thanksf or the review!

    Yes I think this is hard to reach in a functional test, as conn.Disconnect() frees the bufferevent without firing the callback, so this guard only triggers if a libevent disconnect event was already queued when SetNetworkActive(false) runs.

    It's mainly intended to be defensive against an event-loop ordering edge case, and even if it wasn't here, Connect() has its own m_network_active check, but this guard also prevents a misleading "retrying" log message.

    Your p2p_private_broadcast.py change seems like good coverage for the reworked connection initiation path. Happy to include it.

  15. willcl-ark marked this as a draft on Mar 15, 2026
  16. willcl-ark commented at 9:03 PM on March 15, 2026: member

    Drafting this to rework/rebase on #34158, and not undo libevent removal.

  17. willcl-ark force-pushed on Mar 16, 2026
  18. DrahtBot added the label Needs rebase on Mar 23, 2026
  19. willcl-ark force-pushed on Mar 24, 2026
  20. DrahtBot added the label CI failed on Mar 24, 2026
  21. DrahtBot removed the label Needs rebase on Mar 24, 2026
  22. DrahtBot added the label Needs rebase on Mar 26, 2026
  23. net: wire mapport lifecycle to CConnman
    When -networkactive=0 is set, NAT-PMP port mapping was still running and
    attempting gateway queries. Move mapport lifecycle management into
    CConnman, which already owns SetNetworkActive, so it can control mapport
    based on both the -natpmp setting and network state.
    
    EnableMapPort is injected as a callback via CConnman::Options to avoid a
    circular dependency between net and mapport.
    1bf49e5475
  24. test: add test for mapport networkactive
    Add functional test to verify that PCP/NAT-PMP port mapping respects the
    networkactive state:
    
    - Does not run when started with -networkactive=0
    - Starts when network is activated via setnetworkactive RPC
    - Stops when network is deactivated
    - Resumes when network is reactivated
    aef9e74169
  25. net: run tor control based on networkactive
    Wire tor control lifecycle to CConnman on top of the libevent-free tor
    controller being introduced in upstream/pr/34158.
    
    Have CConnman propagate networkactive changes to the node-owned
    TorController and make the controller thread idle while networking is
    disabled instead of attempting Tor control connections or reconnects.
    4a7c8a0d60
  26. test: add torcontrol networkactive coverage
    Add functional coverage for torcontrol when networkactive is disabled at startup and toggled back on later.
    
    Also clear the mock server connection handle on close so the disconnect assertion is reliable.
    25c3185f18
  27. test: check tor control reconnection in p2p_private_broadcast
    Verify that the tor controller attempts reconnection to the control port
    by asserting the retry log message when started with an unreachable
    `-torcontrol` address.
    
    Co-authored-by: brunoerg <brunoerg@users.noreply.github.com>
    e5ed5f279b
  28. willcl-ark force-pushed on Jun 2, 2026
  29. DrahtBot removed the label Needs rebase on Jun 2, 2026
  30. willcl-ark commented at 12:25 PM on June 2, 2026: member

    Sorry I forgot about this while #34158 was in progress. Rebased and undrafted.

  31. willcl-ark marked this as ready for review on Jun 2, 2026
  32. DrahtBot removed the label CI failed on Jun 2, 2026

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: 2026-06-25 16:51 UTC

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