fix: use bitcoind --version for Bitcoin tile version display (works during IBD/startup)
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/63b5dc59-a630-4c14-a6a7-99a71ee517b7 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
d0bf878555
commit
44a7b2a8ab
@@ -1502,6 +1502,9 @@ _BTC_SYNC_CACHE_TTL = 5 # seconds
|
||||
_btc_version_cache: tuple[float, dict | None] = (0.0, None)
|
||||
_BTC_VERSION_CACHE_TTL = 60 # seconds — version doesn't change at runtime
|
||||
|
||||
# Cache for ``bitcoind --version`` output (available even before RPC is ready)
|
||||
_btcd_version_cache: tuple[float, str | None] = (0.0, None)
|
||||
|
||||
|
||||
# ── Generic service version detection (NixOS store path) ─────────
|
||||
|
||||
@@ -1616,6 +1619,57 @@ def _get_bitcoin_version_info() -> dict | None:
|
||||
return None
|
||||
|
||||
|
||||
def _get_bitcoind_version() -> str | None:
|
||||
"""Run ``bitcoind --version`` and return the raw version string, or None on error.
|
||||
|
||||
Parses the first output line to extract the token after "version ".
|
||||
For example: "Bitcoin Knots daemon version v29.3.knots20260210+bip110-v0.4.1"
|
||||
returns "v29.3.knots20260210+bip110-v0.4.1".
|
||||
|
||||
Works regardless of whether the RPC server is ready (IBD, warmup, etc.).
|
||||
Results are cached for 60 seconds (_BTC_VERSION_CACHE_TTL).
|
||||
"""
|
||||
global _btcd_version_cache
|
||||
now = time.monotonic()
|
||||
cached_at, cached_val = _btcd_version_cache
|
||||
if now - cached_at < _BTC_VERSION_CACHE_TTL:
|
||||
return cached_val
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["bitcoind", "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
first_line = result.stdout.splitlines()[0]
|
||||
m = re.search(r"version\s+(v?\S+)", first_line, re.IGNORECASE)
|
||||
if m:
|
||||
ver = m.group(1)
|
||||
_btcd_version_cache = (now, ver)
|
||||
return ver
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
_btcd_version_cache = (now, None)
|
||||
return None
|
||||
|
||||
|
||||
def _format_bitcoin_version(raw_version: str, icon: str = "") -> str:
|
||||
"""Format a raw version string from ``bitcoind --version`` for tile display.
|
||||
|
||||
Strips the ``+bip110-vX.Y.Z`` patch suffix so the base version is shown
|
||||
cleanly (e.g. "v29.3.knots20260210+bip110-v0.4.1" → "v29.3.knots20260210").
|
||||
For the BIP110 tile (icon == "bip110") a " (bip110)" tag is appended.
|
||||
"""
|
||||
# Remove the +bip110... patch suffix that appears in BIP-110 builds
|
||||
display = re.sub(r"\+bip110\S*", "", raw_version)
|
||||
if icon == "bip110" and "(bip110)" not in display.lower():
|
||||
display += " (bip110)"
|
||||
return display
|
||||
|
||||
|
||||
def _get_bitcoin_sync_info() -> dict | None:
|
||||
"""Call bitcoin-cli getblockchaininfo and return parsed JSON, or None on error.
|
||||
|
||||
@@ -1668,16 +1722,15 @@ async def api_bitcoin_sync():
|
||||
async def api_bitcoin_version():
|
||||
"""Return the version string of the active bitcoind implementation."""
|
||||
loop = asyncio.get_event_loop()
|
||||
info = await loop.run_in_executor(None, _get_bitcoin_version_info)
|
||||
if info is None:
|
||||
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
||||
if raw_ver is None:
|
||||
return JSONResponse(
|
||||
status_code=503,
|
||||
content={"error": "bitcoin-cli unavailable or bitcoind not running"},
|
||||
content={"error": "bitcoind --version failed or bitcoind not on PATH"},
|
||||
)
|
||||
subversion = info.get("subversion", "")
|
||||
return {
|
||||
"version": _parse_bitcoin_subversion(subversion),
|
||||
"subversion": subversion,
|
||||
"version": _format_bitcoin_version(raw_ver),
|
||||
"raw_version": raw_ver,
|
||||
}
|
||||
|
||||
|
||||
@@ -1802,12 +1855,9 @@ async def api_services():
|
||||
service_data["sync_blocks"] = sync_blocks
|
||||
service_data["sync_headers"] = sync_headers
|
||||
if unit == "bitcoind.service" and enabled:
|
||||
ver_info = await loop.run_in_executor(None, _get_bitcoin_version_info)
|
||||
if ver_info is not None:
|
||||
subversion = ver_info.get("subversion", "")
|
||||
btc_ver = _parse_bitcoin_subversion(subversion)
|
||||
if icon == "bip110" and "(bip110)" not in btc_ver.lower():
|
||||
btc_ver += " (bip110)"
|
||||
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
||||
if raw_ver is not None:
|
||||
btc_ver = _format_bitcoin_version(raw_ver, icon=icon)
|
||||
service_data["bitcoin_version"] = btc_ver # backwards compat
|
||||
service_data["version"] = btc_ver
|
||||
elif unit != "bitcoind.service":
|
||||
@@ -2088,12 +2138,9 @@ async def api_service_detail(unit: str, icon: str | None = None):
|
||||
service_detail["sync_headers"] = sync_headers
|
||||
if unit == "bitcoind.service" and enabled:
|
||||
loop = asyncio.get_event_loop()
|
||||
ver_info = await loop.run_in_executor(None, _get_bitcoin_version_info)
|
||||
if ver_info is not None:
|
||||
subversion = ver_info.get("subversion", "")
|
||||
btc_ver = _parse_bitcoin_subversion(subversion)
|
||||
if icon == "bip110" and "(bip110)" not in btc_ver.lower():
|
||||
btc_ver += " (bip110)"
|
||||
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
||||
if raw_ver is not None:
|
||||
btc_ver = _format_bitcoin_version(raw_ver, icon=icon)
|
||||
service_detail["bitcoin_version"] = btc_ver # backwards compat
|
||||
service_detail["version"] = btc_ver
|
||||
elif unit != "bitcoind.service":
|
||||
|
||||
Reference in New Issue
Block a user