feat(telemetry): count relayed transactions this node did not process

Moving the tx.receive span past the duplicate check removed the only record of
why a relayed copy was dropped. A labelled counter restores it, and covers the
inner-batch reject the span never usefully reached.

The count itself was never span-derived: transactions_duplicate already totals
the dropped copies and predates the telemetry work. What was missing is the
split between ordinary relay overlap and a peer sending traffic it should not.

A counter also survives sampling and runs with tracing off, which the span
attribute did not.
This commit is contained in:
Pratik Mankawde
2026-09-18 10:00:31 +01:00
parent d029ed9b59
commit f1df5de8dd
2 changed files with 39 additions and 0 deletions

View File

@@ -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.
*/

View File

@@ -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.