From 0bd3d3dfa562724e3dbc4cec2d4290e4561655cd Mon Sep 17 00:00:00 2001 From: Amiti Uttarwar Date: Fri, 8 Sep 2023 16:37:08 -0700 Subject: [PATCH] init: make inbound tx relay percentage configurable Permit users to change the amount of inbounds that are permitted to relay transactions. This is particularly relevant to ensure that superusers that are not concerned with resource usage are not artificially restricted from offering many transaction relay slots to the network. Co-authored-by: Martin Zumsande --- src/init.cpp | 6 ++++-- src/net.h | 7 ++++--- test/functional/p2p_connection_limits.py | 10 ++++++++++ test/functional/p2p_opportunistic_1p1c.py | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 7f708412fd3..c9363ba96dc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -578,11 +578,12 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) argsman.AddArg("-forcednsseed", strprintf("Always query for peer addresses via DNS lookup (default: %u)", DEFAULT_FORCEDNSSEED), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-listen", strprintf("Accept connections from outside (default: %u if no -proxy, -connect or -maxconnections=0)", DEFAULT_LISTEN), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-listenonion", strprintf("Automatically create Tor onion service (default: %d)", DEFAULT_LISTEN_ONION), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-maxconnections=", strprintf("Maintain at most automatic connections to peers (default: %u). %u slots of these are reserved for outgoing connections, %u percent of the remaining ones can support transaction relay. " + argsman.AddArg("-maxconnections=", strprintf("Maintain at most automatic connections to peers (default: %u). %u slots of these are reserved for outgoing connections. See -inboundrelaypercent for more information about limits applied to transaction relay inbound peers. " "This limit does not apply to connections manually added via -addnode or the addnode RPC, which have a separate limit of %u. " "It does not apply to short-lived private broadcast connections either, which have a separate limit of %u.", - DEFAULT_MAX_PEER_CONNECTIONS, MAX_OUTBOUND_FULL_RELAY_CONNECTIONS + MAX_BLOCK_RELAY_ONLY_CONNECTIONS + MAX_FEELER_CONNECTIONS, static_cast(100 * FULL_RELAY_INBOUND_PCT), MAX_ADDNODE_CONNECTIONS, MAX_PRIVATE_BROADCAST_CONNECTIONS), + DEFAULT_MAX_PEER_CONNECTIONS, MAX_OUTBOUND_FULL_RELAY_CONNECTIONS + MAX_BLOCK_RELAY_ONLY_CONNECTIONS + MAX_FEELER_CONNECTIONS, MAX_ADDNODE_CONNECTIONS, MAX_PRIVATE_BROADCAST_CONNECTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-inboundrelaypercent=", strprintf("Permit a maximum percent of inbound connections to relay transactions, to limit memory utilization (0 to 100, default: %u).", DEFAULT_FULL_RELAY_INBOUND_PCT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxreceivebuffer=", strprintf("Maximum per-connection receive buffer, *1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxsendbuffer=", strprintf("Maximum per-connection memory usage for the send buffer, *1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxuploadtarget=", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -2121,6 +2122,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) CConnman::Options connOptions; connOptions.m_local_services = g_local_services; connOptions.m_max_automatic_connections = nMaxConnections; + connOptions.m_full_relay_inbound_percent = std::clamp(args.GetIntArg("-inboundrelaypercent", DEFAULT_FULL_RELAY_INBOUND_PCT), 0, 100); connOptions.uiInterface = &uiInterface; connOptions.m_banman = node.banman.get(); connOptions.m_msgproc = node.peerman.get(); diff --git a/src/net.h b/src/net.h index fa5768cb279..f1814120a31 100644 --- a/src/net.h +++ b/src/net.h @@ -79,8 +79,8 @@ static constexpr size_t MAX_PRIVATE_BROADCAST_CONNECTIONS{64}; static const bool DEFAULT_LISTEN = true; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS{200}; -/** Percentage of inbound connection slots that tx-relaying peers can use */ -static const int FULL_RELAY_INBOUND_PCT{50}; +/** Default percentage of inbound connection slots that tx-relaying peers can use */ +static const int DEFAULT_FULL_RELAY_INBOUND_PCT{50}; /** The default for -maxuploadtarget. 0 = Unlimited */ static const std::string DEFAULT_MAX_UPLOAD_TARGET{"0M"}; /** Default for blocks only*/ @@ -1089,6 +1089,7 @@ public: { ServiceFlags m_local_services = NODE_NONE; int m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS; + int m_full_relay_inbound_percent = DEFAULT_FULL_RELAY_INBOUND_PCT; CClientUIInterface* uiInterface = nullptr; NetEventsInterface* m_msgproc = nullptr; BanMan* m_banman = nullptr; @@ -1124,7 +1125,7 @@ public: m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, m_max_automatic_connections - m_max_outbound_full_relay); m_max_automatic_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + m_max_feeler; m_max_inbound = std::max(0, m_max_automatic_connections - m_max_automatic_outbound); - m_max_inbound_full_relay = std::max(0, static_cast(FULL_RELAY_INBOUND_PCT / 100.0 * m_max_inbound)); + m_max_inbound_full_relay = std::max(0, static_cast(connOptions.m_full_relay_inbound_percent / 100.0 * m_max_inbound)); m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; m_client_interface = connOptions.uiInterface; m_banman = connOptions.m_banman; diff --git a/test/functional/p2p_connection_limits.py b/test/functional/p2p_connection_limits.py index 20e34cabf57..338f8f74f91 100755 --- a/test/functional/p2p_connection_limits.py +++ b/test/functional/p2p_connection_limits.py @@ -58,6 +58,16 @@ class P2PConnectionLimits(BitcoinTestFramework): self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False, expect_success=False) self.wait_until(lambda: len(node.getpeerinfo()) == 2) + self.log.info('Test different values of inboundrelaypercent') + self.restart_node(0, ['-maxconnections=13', '-inboundrelaypercent=0']) + with node.assert_debug_log(['failed to find a tx-relaying eviction candidate - connection dropped'], timeout=2): + self.nodes[0].add_p2p_connection(P2PInterface(), expect_success=False, wait_for_verack=False) + + self.restart_node(0, ['-maxconnections=13', '-inboundrelaypercent=100']) + node.add_p2p_connection(P2PInterface()) + node.add_p2p_connection(P2PInterface()) + self.wait_until(lambda: len(node.getpeerinfo()) == 2) + if __name__ == '__main__': P2PConnectionLimits(__file__).main() diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index 6841d7c3a14..156ffd9a00b 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -76,7 +76,7 @@ class PackageRelayTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[ - "-maxmempool=5","-maxconnections=150" + "-maxmempool=5","-inboundrelaypercent=100" ]] def create_tx_below_mempoolminfee(self, wallet, utxo_to_spend=None):