diff --git a/include/xrpl/telemetry/MetricNames.h b/include/xrpl/telemetry/MetricNames.h index 0de6b1e8fa..bfc3abe0f7 100644 --- a/include/xrpl/telemetry/MetricNames.h +++ b/include/xrpl/telemetry/MetricNames.h @@ -253,6 +253,10 @@ inline constexpr char peerAcceptTotal[] = "peer_accept_total"; * Peer disconnects, by cause and connection direction. */ inline constexpr char peerDisconnectTotal[] = "peer_disconnect_total"; +/** + * Relayed transactions this node did not process, by reason. + */ +inline constexpr char peerTxRejectedTotal[] = "peer_tx_rejected_total"; /** * Peer data requests this node declined to serve, by kind and cause. */ @@ -762,6 +766,22 @@ inline constexpr char graceful[] = "graceful"; inline constexpr char readError[] = "read_error"; } // namespace disconnect +/** + * `peer_tx_rejected_total` reasons -- why a relayed transaction was not + * processed. + * + * `duplicate` is ordinary relay overlap and dominates, because a peer relays + * every transaction it hears. `known_bad` and `inner_batch` mean a peer sent + * traffic it should not, so the split is what separates normal overlap from a + * misbehaving peer. The total across reasons matches the + * `transactions_duplicate` traffic category for the first two. + */ +namespace tx_rejected { +inline constexpr char duplicate[] = "duplicate"; +inline constexpr char knownBad[] = "known_bad"; +inline constexpr char innerBatch[] = "inner_batch"; +} // namespace tx_rejected + /** * `serve_refused_total` request kinds: what the peer had asked for. */ diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 59015bec2e..72d60ec257 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -1428,6 +1428,12 @@ PeerImp::handleTransaction( */ if (stx->isFlag(tfInnerBatchTxn)) { + XRPL_METRIC_COUNTER_INC_LABELED( + app_, + telemetry::metric::peerTxRejectedTotal, + "Relayed transactions not processed, by reason", + {{telemetry::label::reason, + std::string(telemetry::lval::tx_rejected::innerBatch)}}); JLOG(pJournal_.warn()) << "Ignoring Network relayed Tx containing " "tfInnerBatchTxn (handleTransaction)."; fee_.update(resource::kFeeModerateBurdenPeer, "inner batch txn"); @@ -1443,11 +1449,24 @@ PeerImp::handleTransaction( // we have seen this transaction recently if (any(flags & HashRouterFlags::BAD)) { + XRPL_METRIC_COUNTER_INC_LABELED( + app_, + telemetry::metric::peerTxRejectedTotal, + "Relayed transactions not processed, by reason", + {{telemetry::label::reason, + std::string(telemetry::lval::tx_rejected::knownBad)}}); fee_.update(resource::kFeeUselessData, "known bad"); JLOG(pJournal_.debug()) << "Ignoring known bad tx " << txID; } else { + XRPL_METRIC_COUNTER_INC_LABELED( + app_, + telemetry::metric::peerTxRejectedTotal, + "Relayed transactions not processed, by reason", + {{telemetry::label::reason, + std::string(telemetry::lval::tx_rejected::duplicate)}}); + // Erase only if the server has seen this tx. If the server // has not seen this tx then the tx could not have been // queued for this peer.