From 5c78a3312264f79ffd81b627ccf5f7653ac7321c Mon Sep 17 00:00:00 2001 From: frstrtr Date: Wed, 24 Jun 2026 21:29:11 +0000 Subject: [PATCH] web(d-web): emit primary-coin tip in node_topology auto-detect fallback The /api/node_topology auto-detect fallback (used when no per-coin StatsProvider hook is wired) emitted coin/primary/peers/embedded/has_rpc but never height, so the topology card (PR #452 front-end) rendered the primary chain with peers but no tip on fallback nodes. Fill the primary entry with the embedded daemon REAL current block height from the cached template (m_cached_template[height] under m_work_mutex -- the same source rest_local_stats uses), guarded > 0 to match the front-end render guard. synced still requires the StatsProvider hook (is_blockchain_synced() is declared-but-unimplemented), so it is deliberately left to the hook path. Web layer only, no ICoinNode change -> no per-coin/consensus ripple. --- src/core/web_server.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/web_server.cpp b/src/core/web_server.cpp index c827de8be..8c287289e 100644 --- a/src/core/web_server.cpp +++ b/src/core/web_server.cpp @@ -5215,6 +5215,17 @@ nlohmann::json MiningInterface::rest_node_topology() // so a node never advertises a blank primary symbol. std::string primary = node_symbol(); + // Primary coin's REAL current block height from the embedded daemon's cached + // template -- the same source rest_local_stats uses. Lets the auto-detect + // fallback emit "height" (tip) so the topology card shows the primary tip even + // when no per-coin StatsProvider hook is wired. (synced still needs the hook.) + uint64_t primary_height = 0; + { + std::lock_guard lock(m_work_mutex); + if (!m_cached_template.is_null() && m_cached_template.contains("height")) + primary_height = m_cached_template["height"].get(); + } + nlohmann::json coins = nlohmann::json::array(); auto has_coin = [&](const std::string& sym) { for (const auto& c : coins) @@ -5231,6 +5242,10 @@ nlohmann::json MiningInterface::rest_node_topology() // Real embedded/RPC flags for this node's own daemon. entry["embedded"] = (m_coin_node && m_coin_node->is_embedded()); entry["has_rpc"] = (m_coin_node && m_coin_node->has_rpc()); + // Truthful tip from the embedded daemon's cached template (front-end + // renders it only when > 0, so omit a meaningless 0). + if (primary_height > 0) + entry["height"] = primary_height; } coins.push_back(std::move(entry)); };