From 53d0daf3b4a5330d787e3d063e895a3fc8a91020 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:37:00 +0100 Subject: [PATCH] fix(telemetry): preserve deterministic trace_id in round spans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the span-replacement logic in startRoundTracing() that was discarding the hash-derived round span and replacing it with a linked span (which gets a random trace_id). The deterministic trace_id from the ledger hash is the key feature enabling cross-node correlation — replacing it broke correlation on all rounds after the first. Also: use thread_local mt19937 for hashSpan() span IDs (same fix as phase-3 txSpan), add Doxygen to establish tracing method declarations in Consensus.h, and update SpanGuard.h diagram with hashSpan/addEvent. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/libxrpl/telemetry/SpanGuard.cpp | 5 ++--- src/xrpld/app/consensus/RCLConsensus.cpp | 11 ----------- src/xrpld/consensus/Consensus.h | 7 +++++++ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libxrpl/telemetry/SpanGuard.cpp b/src/libxrpl/telemetry/SpanGuard.cpp index 3c325c9db7..b7e06607b6 100644 --- a/src/libxrpl/telemetry/SpanGuard.cpp +++ b/src/libxrpl/telemetry/SpanGuard.cpp @@ -316,10 +316,9 @@ SpanGuard::hashSpan( otel_trace::TraceId traceId(opentelemetry::nostd::span(hashData, 16)); + auto const rval = default_prng()(); std::uint8_t spanIdBytes[8]; - std::random_device rd; - for (auto& b : spanIdBytes) - b = static_cast(rd()); + std::memcpy(spanIdBytes, &rval, sizeof(spanIdBytes)); otel_trace::SpanId spanId(opentelemetry::nostd::span(spanIdBytes, 8)); otel_trace::SpanContext syntheticCtx( diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 356dcf9a8e..76590995d2 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -1183,17 +1183,6 @@ RCLConsensus::Adaptor::startRoundTracing(RCLCxLedger const& prevLgr) if (!*roundSpan_) return; - if (prevRoundContext_.isValid()) - { - // Create a linked span to establish follows-from relationship - // between consecutive rounds, then transfer to roundSpan_. - auto linked = SpanGuard::linkedSpan(cons_span::round, prevRoundContext_); - if (linked) - { - roundSpan_.emplace(std::move(linked)); - } - } - roundSpan_->setAttribute(cons_span::attr::ledgerId, to_string(prevLgr.id()).c_str()); roundSpan_->setAttribute(cons_span::attr::ledgerSeq, static_cast(prevLgr.seq() + 1)); roundSpan_->setAttribute(cons_span::attr::mode, to_string(mode_.load()).c_str()); diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index 5e41242322..59e8d68c5b 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -609,12 +609,19 @@ private: */ std::optional establishSpan_; + /** Create the establish-phase span if not yet active. + * Called on each phaseEstablish() invocation; no-op while span is live. + */ void startEstablishTracing(); + /** Overwrite convergence metrics on the establish span each iteration. + * Final span attributes always reflect the last state before consensus. + */ void updateEstablishTracing(); + /** End the establish span when transitioning to the accepted phase. */ void endEstablishTracing();