net_processing: Provide a 30bpm heartbeat log while inv backlog is in use
What changed, and why it matters
This commit adds a periodic debug log message that prints statistics about Bitcoin's inventory backlog. It is purely an observability/monitoring change and does not alter network behavior, consensus rules, or security boundaries.
No security action required. This is a benign logging-only change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces a 2-second heartbeat log in PeerManagerImpl::ProcessInvBacklog() that emits LogDebug(BCLog::NET) entries showing inbound/outbound inventory backlog sizes and token bucket values once the backlog exceeds 100 items. It adds two constants, one optional member variable, and a guarded logging block. No logic affecting peer state, transaction relay, or resource limits is modified.
Changed components
src/net_processing.cppinventory backlog rate-limiting diagnosticsInspect captured patch +26 / −0
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index ddeac0da..bc90b0c5 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -179,6 +179,10 @@ static constexpr double OUTBOUND_INVENTORY_BUCKET_MULTIPLIER{Ticks<SecondsDouble
static constexpr auto INVENTORY_BUCKET_CHECK_DELAY{100ms};
/** Empty backlog target capacity */
static constexpr size_t INVENTORY_BUCKET_BACKLOG_CAPACITY{300};
+/** Delay between inventory bucket backlog heartbeat log entries */
+static constexpr auto INVENTORY_BUCKET_BACKLOG_HEARTBEAT{2000ms};
+/** Minimum backlog to trigger heartbeat log entries */
+static constexpr size_t INVENTORY_BUCKET_BACKLOG_HEARTBEAT_MIN{100};
/** Average delay between feefilter broadcasts in seconds. */
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL{10min};
/** Maximum feefilter broadcast delay after significant change. */
@@ -1166,6 +1170,7 @@ private:
InvToSendBucket m_inbound_inv_bucket GUARDED_BY(m_inv_to_send_mutex);
InvToSendBucket m_outbound_inv_bucket GUARDED_BY(m_inv_to_send_mutex);
std::atomic<NodeClock::time_point> m_next_inv_bucket_check{NodeClock::time_point::min()};
+ std::optional<NodeClock::time_point> m_next_inv_bucket_heartbeat GUARDED_BY(m_inv_to_send_mutex);
void ProcessInvBacklog(NodeClock::time_point now, bool backlog_bumped=false) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_inv_to_send_mutex);
};
@@ -2378,6 +2383,27 @@ void PeerManagerImpl::ProcessInvBacklog(NodeClock::time_point now, bool backlog_
m_inbound_inv_bucket.increment(now);
m_outbound_inv_bucket.increment(now);
+ // Regular heartbeat logging when there's a backlog
+ if (!m_next_inv_bucket_heartbeat.has_value()) {
+ if (m_inbound_inv_bucket.backlog.size() >= INVENTORY_BUCKET_BACKLOG_HEARTBEAT_MIN || m_outbound_inv_bucket.backlog.size() >= INVENTORY_BUCKET_BACKLOG_HEARTBEAT_MIN) {
+ m_next_inv_bucket_heartbeat = now;
+ }
+ }
+ if (m_next_inv_bucket_heartbeat.has_value() && now >= *m_next_inv_bucket_heartbeat) {
+ LogDebug(BCLog::NET, "Transaction rate-limiting backlog inbound=%d itok=%.1f isz=%.1f outbound=%d otok=%.1f osz=%.1f",
+ m_inbound_inv_bucket.backlog.size(),
+ m_inbound_inv_bucket.count_bucket.value(),
+ m_inbound_inv_bucket.size_bucket.value(),
+ m_outbound_inv_bucket.backlog.size(),
+ m_outbound_inv_bucket.count_bucket.value(),
+ m_outbound_inv_bucket.size_bucket.value());
+ if (m_inbound_inv_bucket.backlog.empty() && m_outbound_inv_bucket.backlog.empty()) {
+ m_next_inv_bucket_heartbeat = std::nullopt;
+ } else {
+ m_next_inv_bucket_heartbeat = now + INVENTORY_BUCKET_BACKLOG_HEARTBEAT;
+ }
+ }
+
// Early exit to skip pointlessly touching mempool lock
bool in_avail = m_inbound_inv_bucket.avail();
bool out_avail = m_outbound_inv_bucket.avail();
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.