From 69693a30e5e18eb0e712654daeda4df85045d1a3 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Tue, 23 Jun 2026 14:22:12 +0000 Subject: [PATCH] web: make /v36_status report real V35->V36 state, not a frozen stub rest_v36_status() returned a hardcoded auto_ratchet.state="voting" with v35_shares=0/v36_shares=0/v36_percentage=0.0 regardless of actual chain state, only ever filling height/sample_size. On a node mid-cross this lied about the V35->V36 transition (the founding-charter stub class) while the sibling rest_version_signaling() already derived the truthful state and percentages from the same chain data. /v36_status now sources auto_ratchet.state and the v35/v36 share counts + percentage from rest_version_signaling(). Non-transition coins (its early {} return) leave truthful zeros; a too-short chain early-returns before the overall_* fields, handled by .value() defaults. Read/web path only; pool aggregates and consensus untouched. Serves the live LTC prod V35->V36 cross (#288) crossing-visibility charter. --- src/core/web_server.cpp | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/core/web_server.cpp b/src/core/web_server.cpp index c439ab7f5..0b8d74aba 100644 --- a/src/core/web_server.cpp +++ b/src/core/web_server.cpp @@ -5959,27 +5959,48 @@ nlohmann::json MiningInterface::rest_version_signaling(const nlohmann::json* cac nlohmann::json MiningInterface::rest_v36_status() { nlohmann::json result = nlohmann::json::object(); + + // Source the real ratchet state + share counts from rest_version_signaling() + // — the canonical, chain-derived V35→V36 computation — so /v36_status never + // lies about the cross. The old body returned a frozen "voting" / 0 v36 + // shares regardless of reality (the founding-charter stub class). On + // non-transition coins version_signaling returns {}, leaving the truthful + // zeros below; on a too-short chain it early-returns before populating the + // overall_* fields, which .value() defaults handle. + nlohmann::json vs = rest_version_signaling(); + + std::string state = "voting"; + if (vs.contains("auto_ratchet") && vs["auto_ratchet"].contains("state")) + state = vs["auto_ratchet"].value("state", std::string("voting")); + result["auto_ratchet"] = { - {"state", "voting"}, - {"persisted_state", ""}, + {"state", state}, + {"persisted_state", state}, {"activated_at", nullptr}, {"activated_height", nullptr}, {"confirmed_at", nullptr} }; - result["share_chain"] = { - {"height", 0}, - {"sample_size", 0}, - {"v35_shares", 0}, - {"v36_shares", 0}, - {"v36_percentage", 0.0} - }; + + int sample_size = vs.value("overall_total", 0); + int v36_shares = vs.value("overall_v36_shares", 0); + int v35_shares = std::max(0, sample_size - v36_shares); + double v36_pct = vs.value("overall_v36_share_pct", 0.0); + + int height = 0; if (m_sharechain_stats_fn) { auto sc = m_sharechain_stats_fn(); - if (sc.contains("chain_height")) - result["share_chain"]["height"] = sc["chain_height"]; - if (sc.contains("total_shares")) - result["share_chain"]["sample_size"] = sc["total_shares"]; + height = sc.value("chain_height", 0); + if (sample_size == 0) + sample_size = sc.value("total_shares", 0); } + + result["share_chain"] = { + {"height", height}, + {"sample_size", sample_size}, + {"v35_shares", v35_shares}, + {"v36_shares", v36_shares}, + {"v36_percentage", v36_pct} + }; return result; }