diff --git a/src/init.cpp b/src/init.cpp index 290f0936807..4eee0ac537d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -710,6 +710,10 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-txsendrate=", + strprintf("Set the maximum ongoing rate for sending transactions to (inbound) peers (default: %u tx/s)", + DEFAULT_TX_SEND_RATE), + ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-privatebroadcast", strprintf( "Broadcast transactions submitted via sendrawtransaction RPC using short-lived " diff --git a/src/net_processing.cpp b/src/net_processing.cpp index bc90b0c513b..56c79c2ca4e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -168,11 +168,6 @@ static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s}; * Use a smaller delay as there is less privacy concern for them. * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */ static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s}; -/** Maximum rate of inventory items to send per second. - * Limits the impact of low-fee transaction floods. */ -[[maybe_unused]] static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND{14}; -/** Target number of tx inventory items to send per transmission. */ -[[maybe_unused]] static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL); /** Multiplier for the inventory bucket rate for outbounds */ static constexpr double OUTBOUND_INVENTORY_BUCKET_MULTIPLIER{Ticks(INBOUND_INVENTORY_BROADCAST_INTERVAL) / Ticks(OUTBOUND_INVENTORY_BROADCAST_INTERVAL)}; /** Delay between checking inventory bucket and backlog */ @@ -531,7 +526,7 @@ struct InvToSendBucket { static constexpr double INBOUND_COUNT_SECONDS{30}; // cap/initial at 30s/mult worth of txs InvToSendBucket(unsigned int rate, double mult) - : count_floor{-1.0 * INVENTORY_BROADCAST_TARGET}, + : count_floor{-1.0 * rate * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL)}, size_bucket(/*rate=*/SIZE_REFILL * mult, /*value=*/SIZE_INIT, /*cap=*/SIZE_CAP), count_bucket(/*rate=*/rate * mult, /*value=*/rate * INBOUND_COUNT_SECONDS, /*cap=*/rate * INBOUND_COUNT_SECONDS) { @@ -2112,8 +2107,8 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, m_txdownloadman(node::TxDownloadOptions{pool, m_rng, opts.deterministic_rng}), m_warnings{warnings}, m_opts{opts}, - m_inbound_inv_bucket(/*rate=*/INVENTORY_BROADCAST_PER_SECOND, /*mult=*/1.0), - m_outbound_inv_bucket(/*rate=*/INVENTORY_BROADCAST_PER_SECOND, /*mult=*/OUTBOUND_INVENTORY_BUCKET_MULTIPLIER) + m_inbound_inv_bucket(/*rate=*/m_opts.tx_send_rate, /*mult=*/1.0), + m_outbound_inv_bucket(/*rate=*/m_opts.tx_send_rate, /*mult=*/OUTBOUND_INVENTORY_BUCKET_MULTIPLIER) { // While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation. // This argument can go away after Erlay support is complete. diff --git a/src/net_processing.h b/src/net_processing.h index f29adc0157f..8e6c4b87f85 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -42,6 +42,8 @@ static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false}; /** Default number of non-mempool transactions to keep around for block reconstruction. Includes orphan, replaced, and rejected transactions. */ static const uint32_t DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN{100}; +/** Default maximum per-second rate for sending transaction inventory to peers. */ +static constexpr unsigned int DEFAULT_TX_SEND_RATE{14}; static const bool DEFAULT_PEERBLOOMFILTERS = false; static const bool DEFAULT_PEERBLOCKFILTERS = false; /** Maximum number of outstanding CMPCTBLOCK requests for the same block. */ @@ -96,6 +98,8 @@ public: uint32_t max_headers_result{MAX_HEADERS_RESULTS}; //! Whether private broadcast is used for sending transactions. bool private_broadcast{DEFAULT_PRIVATE_BROADCAST}; + //! Maximum per-second rate for sending transaction inventory to peers. + unsigned int tx_send_rate{DEFAULT_TX_SEND_RATE}; }; static std::unique_ptr make(CConnman& connman, AddrMan& addrman, diff --git a/src/node/peerman_args.cpp b/src/node/peerman_args.cpp index 9745d69d5ae..47413af0ce5 100644 --- a/src/node/peerman_args.cpp +++ b/src/node/peerman_args.cpp @@ -24,6 +24,10 @@ void ApplyArgsManOptions(const ArgsManager& argsman, PeerManager::Options& optio if (auto value{argsman.GetBoolArg("-blocksonly")}) options.ignore_incoming_txs = *value; + if (auto value{argsman.GetIntArg("-txsendrate")}) { + options.tx_send_rate = uint32_t(std::clamp(*value, 1, 1000)); + } + if (auto value{argsman.GetBoolArg("-privatebroadcast")}) options.private_broadcast = *value; } diff --git a/src/node/txdownloadman.h b/src/node/txdownloadman.h index 2cc1ec2c279..bef1d162d22 100644 --- a/src/node/txdownloadman.h +++ b/src/node/txdownloadman.h @@ -25,7 +25,7 @@ class TxDownloadManagerImpl; static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT = 100; /** Maximum number of transactions to consider for requesting, per peer. It provides a reasonable DoS limit to * per-peer memory usage spent on announcements, while covering peers continuously sending INVs at the maximum - * rate (by our own policy, see INVENTORY_BROADCAST_PER_SECOND) for several minutes, while not receiving + * rate (by our own policy, see DEFAULT_TX_SEND_RATE) for several minutes, while not receiving * the actual transaction (from any peer) in response to requests for them. */ static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 5000; /** How long to delay requesting transactions via txids, if we have wtxid-relaying peers */