diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8ea8b..fc0c1a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed -- Fix Bitcoin Knots → Bitcoin Core switch hanging in the Hub UI - Sessions are now persisted to `/var/lib/secrets/hub-sessions.json` so the browser login survives the Hub service restart that `nixos-rebuild switch` performs during activation. Previously the in-memory session store was @@ -243,7 +242,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Integrated Sparrow Wallet, Bisq, and Bisq 2 - Comprehensive Sovran Hub for service management - NixOS-based operating system with privacy and sovereignty focus -- Support for Bitcoin Knots + BIP110, Electrs, LND, Ride The Lightning, BTCPay Server, and more +- Support for Bitcoin Core, Electrs, LND, Ride The Lightning, BTCPay Server, and more - Server + Desktop hybrid mode with Matrix, Nextcloud, VaultWarden, and other self-hosted services - Automated installer with graphical GNOME desktop - Tor integration and onion services for all major components diff --git a/README.md b/README.md index 03011dc..0b4e353 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,7 @@ Sovran_SystemsOS solves both with one operating system: - **Buy and sell Bitcoin peer-to-peer** with Bisq and Bisq 2. No central company holds user funds, and no exchange account stands between buyers and sellers. -- **Verify your own Bitcoin** with a full node: [Bitcoin - Knots](https://bitcoinknots.org) and +- **Verify your own Bitcoin** with a full node: [Bitcoin Core](https://bitcoin.org) and [Electrs](https://github.com/romanz/electrs), so your wallets connect to *your* node instead of a stranger's. - **Use Lightning** with [LND](https://github.com/lightningnetwork/lnd) and @@ -150,13 +149,13 @@ presents and manages the features available on your system. ### Your money — Bitcoin sovereignty -- Bitcoin Knots, Electrs, and Tor integration +- Bitcoin Core, Electrs, and Tor integration - LND and Ride The Lightning, with [Alby Hub](https://albyhub.com) for Nostr Wallet Connect (NWC) connections - BTCPay Server - Sparrow Wallet, Bisq, and Bisq 2, with automatic wallet-to-node connections - Optional: a self-hosted [Mempool](https://github.com/mempool/mempool) - explorer, or Bitcoin Core in place of Knots + explorer Run your own Bitcoin infrastructure. Verify your own money. Trust no one. @@ -202,7 +201,7 @@ Bitcoin and self-hosting infrastructure runs on the machine. | Mode | Best for | What you get | |---|---|---| | **Desktop** | Everyday users and computers with modest hardware | Sparrow, Bisq, and Bisq 2 for self-custody and peer-to-peer Bitcoin use | -| **Node** | People ready to verify and operate their own Bitcoin infrastructure | Everything in Desktop, plus the full Bitcoin stack: Bitcoin Knots, Electrs, LND, Ride The Lightning, BTCPay Server, and wallet-to-node connections | +| **Node** | People ready to verify and operate their own Bitcoin infrastructure | Everything in Desktop, plus the full Bitcoin stack: Bitcoin Core, Electrs, LND, Ride The Lightning, BTCPay Server, and wallet-to-node connections | | **Server + Desktop** | Bitcoiners who want the same sovereignty over their communications, cloud, passwords, and web services | The complete Node stack, plus the private self-hosted services | **Desktop: start with your keys.** Desktop is not a reduced or Bitcoin-free @@ -688,7 +687,6 @@ rebuilds the machine into the selected declarative state. | Shared credentials | `modules/credentials.nix` | | Bitcoin and Lightning stack | `modules/bitcoinecosystem.nix` | | Automatic wallet-to-node connections | `modules/wallet-autoconnect.nix` | -| Optional Bitcoin Core in place of Knots | `modules/bitcoin-core.nix` | | Alby Hub and Nostr Wallet Connect (NWC) on LND | `modules/nwc-wallets.nix`, `packages/albyhub/` | | Matrix Synapse | `modules/synapse.nix` | | Optional Element audio and video calling via LiveKit | `modules/element-calling.nix` | @@ -777,7 +775,6 @@ This work helps make it possible for Sovran_SystemsOS to deliver self-custody an Sovran_SystemsOS also depends on the work of the developers and communities behind: -- [Bitcoin Knots](https://github.com/bitcoinknots/bitcoin) - [Bitcoin Core](https://github.com/bitcoin/bitcoin) - [Sparrow Wallet](https://github.com/sparrowwallet/sparrow) - [Bisq](https://github.com/bisq-network/bisq) diff --git a/app/icons/bip110.svg b/app/icons/bip110.svg deleted file mode 100644 index 4fcc163..0000000 --- a/app/icons/bip110.svg +++ /dev/null @@ -1,244 +0,0 @@ - - - diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index 0c54164..687d17a 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -149,7 +149,6 @@ SESSION_MAX_AGE = 86400 # 24 hours # Sessions are persisted here so logins survive a restart of the Hub service. # nixos-rebuild switch restarts sovran-hub-web.service during activation (its # unit definition changes with every feature toggle — e.g. the Bitcoin -# Knots → Core switch changes services.bitcoind.package, which is on the Hub's # PATH). Without persistence the browser session dies mid-rebuild, the # /api/rebuild/status polling starts receiving 401s and the rebuild modal # hangs forever showing "Applying changes…". The file lives in @@ -318,18 +317,6 @@ FEATURE_REGISTRY = [ "conflicts_with": [], "port_requirements": [], }, - { - "id": "bitcoin-core", - "name": "Bitcoin Core", - "description": "Only one Bitcoin node implementation can be active: Bitcoin Knots + BIP110 (default) or Bitcoin Core. Enabling this replaces Knots + BIP110 with Bitcoin Core. Your timechain data is preserved.", - "category": "bitcoin", - "needs_domain": False, - "domain_name": None, - "needs_ddns": False, - "extra_fields": [], - "conflicts_with": [], - "port_requirements": [], - }, { "id": "sshd", "name": "SSH Remote Access", @@ -363,7 +350,7 @@ FEATURE_REGISTRY = [ # Feature ids that have been removed/deprecated. The Hub must never write these # back into custom.nix, and should strip any it finds (see startup migration). -DEPRECATED_FEATURE_IDS: set[str] = {"bip110"} +DEPRECATED_FEATURE_IDS: set[str] = {"bitcoin-core"} # Map feature IDs to their systemd units in config.json FEATURE_SERVICE_MAP = { @@ -371,7 +358,6 @@ FEATURE_SERVICE_MAP = { "haven": "haven-relay.service", "element-calling": "livekit.service", "mempool": "mempool.service", - "bitcoin-core": None, "btcpay-web": "btcpayserver.service", "nwc-wallets": "albyhub.service", "sshd": "sshd.service", @@ -426,9 +412,7 @@ SERVICE_DOMAIN_MAP: dict[str, str] = { } # For features that share a unit, disambiguate by icon field -FEATURE_ICON_MAP = { - "bitcoin-core": "bitcoin-core", -} +FEATURE_ICON_MAP: dict[str, str] = {} ROLE_LABELS = { "server_plus_desktop": "Server + Desktop", @@ -447,7 +431,7 @@ ROLE_CATEGORIES: dict[str, set[str] | None] = { ROLE_FEATURES: dict[str, set[str] | None] = { "server_plus_desktop": None, "desktop": {"rdp", "sshd"}, - "node": {"rdp", "bitcoin-core", "mempool", "btcpay-web", "nwc-wallets", "sshd"}, + "node": {"rdp", "mempool", "btcpay-web", "nwc-wallets", "sshd"}, } SERVICE_DESCRIPTIONS: dict[str, str] = { @@ -2080,7 +2064,7 @@ def _is_feature_enabled_in_config(feature_id: str) -> bool | None: return False # Default off in Node role; only on via explicit hub toggle unit = FEATURE_SERVICE_MAP.get(feature_id) if unit is None: - return None # bitcoin-core — can't determine from config + return None cfg = load_config() for svc in cfg.get("services", []): if svc.get("unit") == unit: @@ -2823,21 +2807,11 @@ BITCOIN_DATADIR = "/run/media/Second_Drive/BTCEcoandBackup/Bitcoin_Node" _btc_sync_cache: tuple[float, dict | None] = (0.0, None) _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) -# Cache for ``bitcoin-cli getdeploymentinfo`` output (BIP-110 live status) -_btc_deployment_cache: tuple[float, dict | None] = (0.0, None) - -# Bitcoin Knots exposes BIP-110 as the `reduced_data` versionbits deployment -# (RDTS, bit 4) in getdeploymentinfo. See Knots src/deploymentinfo.cpp, -# src/kernel/chainparams.cpp, and doc/bips.md. -BIP110_DEPLOYMENT_NAMES = {"reduced_data", "rdts", "bip110", "uasf-bip110"} -BIP110_VERSIONBITS_BIT = 4 -BIP110_SUBVERSION_MARKERS = {"bip110", "uasf-bip110", "reduced_data", "rdts"} # ── Generic service version detection (NixOS store path) ───────── @@ -2963,213 +2937,12 @@ def _get_service_version(unit: str) -> str | None: return version -def _parse_bitcoin_subversion(subversion: str) -> str: - """Parse a subversion string like '/Bitcoin Knots:27.1.0/' into 'v27.1.0'. - - Examples: - '/Bitcoin Knots:27.1.0/' → 'v27.1.0' - '/Satoshi:27.0.0/' → 'v27.0.0' - '/Bitcoin Knots:27.1.0(bip110)/' → 'v27.1.0 (bip110)' - Falls back to the raw subversion string if parsing fails. - """ - m = re.search(r":(\d+\.\d+(?:\.\d+)*)", subversion) - if m: - ver = "v" + m.group(1) - if "(bip110)" in subversion.lower(): - ver += " (bip110)" - return ver - return subversion - - -def _get_bitcoin_version_info() -> dict | None: - """Call bitcoin-cli getnetworkinfo and return parsed JSON, or None on error. - - Results are cached for _BTC_VERSION_CACHE_TTL seconds since the version - does not change while the service is running. - """ - global _btc_version_cache - now = time.monotonic() - cached_at, cached_val = _btc_version_cache - if now - cached_at < _BTC_VERSION_CACHE_TTL: - return cached_val - - try: - result = subprocess.run( - ["bitcoin-cli", f"-datadir={BITCOIN_DATADIR}", "getnetworkinfo"], - capture_output=True, - text=True, - # This is a dashboard hint; do not make an unavailable RPC delay - # the entire service tile response. - timeout=3, - ) - if result.returncode != 0: - _btc_version_cache = (now, None) - return None - info = json.loads(result.stdout) - _btc_version_cache = (now, info) - return info - except Exception: - _btc_version_cache = (now, None) - return None - - -def _get_bitcoin_deployment_info() -> dict | None: - """Call bitcoin-cli getdeploymentinfo and return parsed JSON, or None on error. - - Results are cached for _BTC_VERSION_CACHE_TTL seconds. Never raises. - """ - global _btc_deployment_cache - now = time.monotonic() - cached_at, cached_val = _btc_deployment_cache - if now - cached_at < _BTC_VERSION_CACHE_TTL: - return cached_val - - try: - result = subprocess.run( - ["bitcoin-cli", f"-datadir={BITCOIN_DATADIR}", "getdeploymentinfo"], - capture_output=True, - text=True, - # BIP-110 is supplementary tile metadata; an RPC timeout must not - # block the dashboard from rendering. - timeout=3, - ) - if result.returncode != 0: - _btc_deployment_cache = (now, None) - return None - info = json.loads(result.stdout) - _btc_deployment_cache = (now, info) - return info - except Exception: - _btc_deployment_cache = (now, None) - return None - - -def _get_bip110_status() -> dict: - """Return a dict describing the live BIP-110 deployment/signaling state. - - The returned struct has four stable keys:: - - { - "supported": bool, # node build is BIP-110-capable - "signaling": bool, # node is actively signaling / locked-in / active - "state": str, # "active" | "locked_in" | "signaling" | - # "not_signaling" | "unsupported" | "unknown" - "source": str, # "getdeploymentinfo" | "subversion" | "none" - } - - Resolution order (authoritative → fallback → honest unknown): - - 1. ``getdeploymentinfo`` (authoritative) — scan ``deployments`` for BIP-110. - Bitcoin Knots currently exposes BIP-110 as ``reduced_data`` (RDTS, bit 4; - see Knots deploymentinfo.cpp / chainparams.cpp / doc/bips.md), so matching - first uses known deployment names, then falls back to versionbits bit 4. - - 2. Subversion fallback — if getdeploymentinfo is unavailable or yields no - recognisable BIP-110 entry, inspect the ``subversion`` field from - ``getnetworkinfo``. A case-insensitive match for known BIP-110 markers - (including "bip110", "uasf-bip110", "reduced_data", "rdts") is treated as - "signaling". - - 3. Unknown — if the node is entirely unreachable or neither source is - conclusive, return state="unknown", signaling=False, source="none". - """ - _unknown: dict = {"supported": False, "signaling": False, "state": "unknown", "source": "none"} - - def _deployment_bit(entry: dict) -> int | None: - bip9 = entry.get("bip9", {}) or {} - bip8 = entry.get("bip8", {}) or {} - bit = bip9.get("bit") - if bit is None: - bit = bip8.get("bit") - if bit is None: - bit = entry.get("bit") - return bit - - # ── 1. getdeploymentinfo (authoritative) ────────────────────────── - deploy_info = _get_bitcoin_deployment_info() - if deploy_info is not None: - deployments = deploy_info.get("deployments", {}) - if isinstance(deployments, dict): - matched_entry: dict | None = None - - # Primary match: known deployment names (case-insensitive exact match) - for key, entry in deployments.items(): - if not isinstance(entry, dict): - continue - key_lower = key.lower() - if key_lower not in BIP110_DEPLOYMENT_NAMES: - continue - matched_entry = entry - break - - # Secondary match: versionbits bit (fallback only) - if matched_entry is None: - for _, entry in deployments.items(): - if not isinstance(entry, dict): - continue - if _deployment_bit(entry) != BIP110_VERSIONBITS_BIT: - continue - matched_entry = entry - break - - if matched_entry is not None: - entry = matched_entry - - # bip9 / bip8 status field - bip9 = entry.get("bip9", {}) or {} - bip8 = entry.get("bip8", {}) or {} - status = ( - bip9.get("status") - or bip8.get("status") - or entry.get("status") - or "" - ).lower() - active = entry.get("active", False) - - if active or status == "active": - return {"supported": True, "signaling": True, "state": "active", "source": "getdeploymentinfo"} - if status == "locked_in": - return {"supported": True, "signaling": True, "state": "locked_in", "source": "getdeploymentinfo"} - if status in ("started", "defined"): - # Check whether deployment is currently signaling in this period. - stats = bip9.get("statistics") or bip8.get("statistics") or {} - # Some Knots outputs expose only ``count`` (not explicit signaling bool), - # so treat count>0 as a conservative signaling indicator for this period. - count = stats.get("count") - signaling = bool( - stats.get("signaling") - or stats.get("signalling") - or (isinstance(count, int) and count > 0) - ) - if signaling: - return {"supported": True, "signaling": True, "state": "signaling", "source": "getdeploymentinfo"} - return {"supported": True, "signaling": False, "state": "not_signaling", "source": "getdeploymentinfo"} - if status == "failed": - return {"supported": True, "signaling": False, "state": "not_signaling", "source": "getdeploymentinfo"} - # Entry found but status unrecognised — node supports BIP-110 but state unclear - return {"supported": True, "signaling": False, "state": "unknown", "source": "getdeploymentinfo"} - - # ── 2. Subversion fallback ───────────────────────────────────────── - net_info = _get_bitcoin_version_info() - if net_info is not None: - subversion = net_info.get("subversion", "") or "" - sv_lower = subversion.lower() - if any(marker in sv_lower for marker in BIP110_SUBVERSION_MARKERS): - return {"supported": True, "signaling": True, "state": "signaling", "source": "subversion"} - # Node is reachable via RPC but no BIP-110 marker found anywhere - return {"supported": False, "signaling": False, "state": "unsupported", "source": "subversion"} - - # ── 3. Node unreachable / RPC not ready ─────────────────────────── - return _unknown 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.knots20260508" - returns "v29.3.knots20260508". - Works regardless of whether the RPC server is ready (IBD, warmup, etc.). Results are cached for 60 seconds (_BTC_VERSION_CACHE_TTL). """ @@ -3200,17 +2973,9 @@ def _get_bitcoind_version() -> str | None: return None -def _format_bitcoin_version(raw_version: str, icon: str = "") -> str: - """Format a raw version string from ``bitcoind --version`` for tile display. - - For the BIP110 tile (icon == "bip110") a " (bip110)" tag is appended, - since mainline Bitcoin Knots (29.3.knots20260508+) now includes BIP-110 - and no longer carries a separate ``+bip110-vX.Y.Z`` suffix. - """ - display = raw_version - if icon == "bip110" and "(bip110)" not in display.lower(): - display += " (bip110)" - return display +def _format_bitcoin_version(raw_version: str) -> str: + """Format a raw version string from ``bitcoind --version`` for display.""" + return raw_version def _get_bitcoin_sync_info() -> dict | None: @@ -3279,19 +3044,6 @@ async def api_bitcoin_version(): } -@app.get("/api/bitcoin/bip110") -async def api_bitcoin_bip110(): - """Return live BIP-110 deployment/signaling status from bitcoin-cli. - - Always returns HTTP 200. When bitcoind is unreachable or the node is mid-IBD - the response will contain ``state = "unknown"`` so the UI can render a neutral - badge rather than an error toast. - """ - loop = asyncio.get_event_loop() - status = await loop.run_in_executor(None, _get_bip110_status) - return status - - @app.get("/api/services") async def api_services(): started_at = time.monotonic() @@ -3371,39 +3123,27 @@ async def api_services(): dns_states_future = asyncio.gather( *(resolve_domain(domain) for domain in sorted(domain_names)) ) - # Bitcoin sync and BIP-110 are supplementary tile metadata. Fetch each - # once, concurrently with the other diagnostics, instead of doing duplicate - # RPC calls inside both bitcoind tile coroutines. + # Bitcoin sync is supplementary tile metadata. Fetch it once alongside + # the other diagnostics instead of duplicating RPC calls per tile. has_enabled_bitcoin = any( entry.get("unit") == "bitcoind.service" and enabled for entry, enabled in effective_entries ) - has_enabled_bip110 = any( - entry.get("icon") == "bip110" and enabled - for entry, enabled in effective_entries - ) bitcoin_sync_future = ( loop.run_in_executor(None, _get_bitcoin_sync_info) if has_enabled_bitcoin else asyncio.sleep(0, result=None) ) - bip110_future = ( - loop.run_in_executor(None, _get_bip110_status) - if has_enabled_bip110 - else asyncio.sleep(0, result=None) - ) ( active_states, port_states, dns_states, bitcoin_sync_info, - bip110_status, ) = await asyncio.gather( active_states_future, port_states_future, dns_states_future, bitcoin_sync_future, - bip110_future, ) listening_ports, firewall_ports = port_states resolved_domains = dict(dns_states) @@ -3559,11 +3299,9 @@ async def api_services(): if unit == "bitcoind.service" and enabled: 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) + btc_ver = _format_bitcoin_version(raw_ver) service_data["bitcoin_version"] = btc_ver # backwards compat service_data["version"] = btc_ver - if icon == "bip110" and bip110_status is not None: - service_data["bip110"] = bip110_status # ── Generic version for all services (Nix store path) ────────── if enabled and unit and "version" not in service_data: ver = await loop.run_in_executor(None, _get_service_version, unit) @@ -3840,11 +3578,9 @@ async def api_service_detail(unit: str, icon: str | None = None): loop = asyncio.get_event_loop() 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) + btc_ver = _format_bitcoin_version(raw_ver) service_detail["bitcoin_version"] = btc_ver # backwards compat service_detail["version"] = btc_ver - if icon == "bip110": - service_detail["bip110"] = await loop.run_in_executor(None, _get_bip110_status) # ── Generic version for all services (Nix store path) ────────── if enabled and unit and "version" not in service_detail: ver = await loop.run_in_executor(None, _get_service_version, unit) @@ -6325,8 +6061,7 @@ async def _startup_recover_stale_status(): @app.on_event("startup") async def _startup_migrate_deprecated_features(): - """Strip deprecated feature lines (e.g. bip110) from the Hub Managed section - of custom.nix so they are never re-written and do not cause stale warnings.""" + """Strip deprecated feature lines from the Hub Managed section of custom.nix.""" loop = asyncio.get_event_loop() await loop.run_in_executor(None, _migrate_strip_deprecated_features) diff --git a/app/sovran_systemsos_web/static/css/tiles.css b/app/sovran_systemsos_web/static/css/tiles.css index 2047da7..91589fc 100644 --- a/app/sovran_systemsos_web/static/css/tiles.css +++ b/app/sovran_systemsos_web/static/css/tiles.css @@ -178,68 +178,6 @@ white-space: nowrap; } -/* ── BIP-110 status badge (tile + detail modal) ───────────────────── */ - -.tile-bip110-badge { - display: inline-flex; - align-items: center; - gap: 3px; - font-size: 0.64rem; - font-weight: 600; - border-radius: 4px; - padding: 2px 6px; - margin-top: 4px; - white-space: nowrap; - letter-spacing: 0.02em; -} - -.tile-bip110-badge--active { - background: rgba(109, 191, 139, 0.18); - color: var(--green); - border: 1px solid rgba(109, 191, 139, 0.3); -} - -.tile-bip110-badge--locked_in { - background: rgba(94, 173, 138, 0.15); - color: var(--accent-color); - border: 1px solid rgba(94, 173, 138, 0.3); -} - -.tile-bip110-badge--signaling { - background: rgba(94, 173, 138, 0.12); - color: var(--accent-color); - border: 1px solid rgba(94, 173, 138, 0.2); -} - -.tile-bip110-badge--not_signaling { - background: rgba(229, 165, 10, 0.12); - color: var(--yellow); - border: 1px solid rgba(229, 165, 10, 0.25); -} - -.tile-bip110-badge--unsupported { - background: rgba(94, 122, 106, 0.12); - color: var(--grey); - border: 1px solid rgba(94, 122, 106, 0.2); -} - -.tile-bip110-badge--unknown { - background: transparent; - color: var(--text-dim); - border: 1px solid var(--border-color); -} - -.bip110-status-row { - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; -} - -.bip110-source-label { - color: var(--text-dim); - font-size: 0.75rem; -} /* ── Service detail modal sections ───────────────────────────────── */ diff --git a/app/sovran_systemsos_web/static/js/features.js b/app/sovran_systemsos_web/static/js/features.js index 79082b0..6060973 100644 --- a/app/sovran_systemsos_web/static/js/features.js +++ b/app/sovran_systemsos_web/static/js/features.js @@ -403,10 +403,7 @@ function handleFeatureToggle(feat, newEnabled) { openPortRequirementsModal(feat.name, ports, proceedAfterPortCheck); } - if (feat.id === "bitcoin-core") { - var confirmMsg = "Only one Bitcoin node implementation can be active. Enabling Bitcoin Core will replace Bitcoin Knots + BIP110 as the active node. Your timechain data will be preserved — you will not need to re-download the timechain. Continue?"; - openFeatureConfirm(confirmMsg, proceedAfterConflictCheck); - } else if (conflictNames.length > 0) { + if (conflictNames.length > 0) { openFeatureConfirm("This will disable " + conflictNames.join(", ") + ". Continue?", proceedAfterConflictCheck); } else { proceedAfterConflictCheck(); diff --git a/app/sovran_systemsos_web/static/js/helpers.js b/app/sovran_systemsos_web/static/js/helpers.js index 494990b..de1b17d 100644 --- a/app/sovran_systemsos_web/static/js/helpers.js +++ b/app/sovran_systemsos_web/static/js/helpers.js @@ -133,17 +133,3 @@ async function apiFetch(path, options) { } return res.json(); } - - -// ── BIP-110 badge state config ──────────────────────────────────── -// Shared lookup used by tiles.js and service-detail.js. -// Keys match the "state" values returned by /api/bitcoin/bip110. - -var BIP110_BADGE_CONFIG = { - active: { cls: 'tile-bip110-badge--active', label: 'Active', title: 'BIP-110 is active on this node' }, - locked_in: { cls: 'tile-bip110-badge--locked_in', label: 'Locked In', title: 'BIP-110 is locked in and will activate shortly' }, - signaling: { cls: 'tile-bip110-badge--signaling', label: 'Signaling', title: 'Node is signaling readiness for BIP-110' }, - not_signaling: { cls: 'tile-bip110-badge--not_signaling',label: 'Not Signaling', title: 'Node supports BIP-110 but is not signaling this period' }, - unsupported: { cls: 'tile-bip110-badge--unsupported', label: 'Not Supported', title: 'This node build does not include BIP-110' }, - unknown: { cls: 'tile-bip110-badge--unknown', label: '\u2014', title: 'Status unavailable (node syncing or RPC not ready)' } -}; diff --git a/app/sovran_systemsos_web/static/js/service-detail.js b/app/sovran_systemsos_web/static/js/service-detail.js index f787284..2fba031 100644 --- a/app/sovran_systemsos_web/static/js/service-detail.js +++ b/app/sovran_systemsos_web/static/js/service-detail.js @@ -704,20 +704,6 @@ async function openServiceDetailModal(unit, name, icon) { '' + ''); - // Section B2: BIP-110 live status (bip110 tile only) - if (icon === 'bip110' && data.bip110) { - var bip110 = data.bip110; - var bip110State = bip110.state || 'unknown'; - var bip110Cfg = BIP110_BADGE_CONFIG[bip110State] || BIP110_BADGE_CONFIG.unknown; - var bip110Source = bip110.source ? ' (source: ' + escHtml(bip110.source) + ')' : ''; - html += '
' + - '
BIP-110 Deployment Status
' + - '
' + - '' + escHtml(bip110Cfg.label) + '' + - bip110Source + - '
' + - '
'; - } // Section C: Domain diagnostics (domain services) if (data.needs_domain) { @@ -901,9 +887,7 @@ async function openServiceDetailModal(unit, name, icon) { var addonBtnCls = feat.enabled ? "btn btn-close-modal" : "btn btn-primary"; // Section title: use a more specific label for mutually-exclusive Bitcoin node features - var addonSectionTitle = (feat.id === "bitcoin-core") - ? "\u20BF Bitcoin Node Selection" - : "\uD83D\uDD27 Addon Feature"; + var addonSectionTitle = "\uD83D\uDD27 Addon Feature"; // Description: prefer the feature's own description over a generic fallback var addonDesc = feat.description diff --git a/app/sovran_systemsos_web/static/js/tiles.js b/app/sovran_systemsos_web/static/js/tiles.js index c1a6d97..5a24772 100644 --- a/app/sovran_systemsos_web/static/js/tiles.js +++ b/app/sovran_systemsos_web/static/js/tiles.js @@ -4,14 +4,6 @@ // Keyed by tileId: { progress: float, timestamp: ms } var _btcSyncPrev = {}; -// ── BIP-110 badge helper ────────────────────────────────────────── - -function _renderBip110Badge(bip110) { - if (!bip110) return ''; - var state = bip110.state || 'unknown'; - var cfg = BIP110_BADGE_CONFIG[state] || BIP110_BADGE_CONFIG.unknown; - return '
' + escHtml(cfg.label) + '
'; -} function _firstElementFromHtml(html) { var tmp = document.createElement("div"); @@ -175,8 +167,7 @@ function buildTile(svc) { return tile; } - var bip110Badge = (svc.icon === 'bip110') ? _renderBip110Badge(svc.bip110) : ''; - tile.innerHTML = '' + escHtml(svc.name) + '
' + escHtml(svc.name) + '
' + bip110Badge + '
' + st + '
'; + tile.innerHTML = '' + escHtml(svc.name) + '
' + escHtml(svc.name) + '
' + st + '
'; tile.style.cursor = "pointer"; tile.addEventListener("click", function() { @@ -244,23 +235,6 @@ function updateTiles(services) { var text = tile.querySelector(".status-text"); if (dot) dot.className = "status-dot " + sc; if (text) text.textContent = st; - // Update BIP-110 badge for bip110 tiles - if (svc.icon === 'bip110') { - var badgeHtml = _renderBip110Badge(svc.bip110); - var badgeEl = tile.querySelector(".tile-bip110-badge"); - if (badgeEl) { - // Replace existing badge in-place - var newBadge = _firstElementFromHtml(badgeHtml); - if (newBadge) { badgeEl.replaceWith(newBadge); } else { badgeEl.remove(); } - } else if (badgeHtml) { - // Insert badge after the service name - var anchorEl = tile.querySelector(".tile-name"); - if (anchorEl) { - var newBadgeEl = _firstElementFromHtml(badgeHtml); - if (newBadgeEl) anchorEl.insertAdjacentElement("afterend", newBadgeEl); - } - } - } } } } diff --git a/modules/bitcoin-core.nix b/modules/bitcoin-core.nix deleted file mode 100755 index 2794d57..0000000 --- a/modules/bitcoin-core.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ config, pkgs, lib, ... }: - -lib.mkIf config.sovran_systemsOS.features.bitcoin-core { - # Vendored nix-bitcoin now uses nixpkgs directly; no nix-bitcoin.pkgs indirection. - # Use standard bitcoind from nixpkgs (override to knots if desired via pkgs.bitcoind-knots) - services.bitcoind.package = lib.mkForce pkgs.bitcoind; -} diff --git a/modules/bitcoin/bitcoind.nix b/modules/bitcoin/bitcoind.nix index 4a3ff3b..a6f137f 100644 --- a/modules/bitcoin/bitcoind.nix +++ b/modules/bitcoin/bitcoind.nix @@ -62,11 +62,6 @@ let description = '' The package providing bitcoind binaries. - You can use this option to select other bitcoind-compatible implementations. - Example: - ```nix - services.bitcoind.package = pkgs.bitcoind-knots; - ``` ''; }; extraConfig = mkOption { diff --git a/modules/bitcoinecosystem.nix b/modules/bitcoinecosystem.nix index 205057c..a48047b 100755 --- a/modules/bitcoinecosystem.nix +++ b/modules/bitcoinecosystem.nix @@ -4,7 +4,7 @@ lib.mkIf config.sovran_systemsOS.services.bitcoin { services.bitcoind = { enable = true; - package = pkgs.bitcoind-knots; + package = pkgs.bitcoind; dataDir = "/run/media/Second_Drive/BTCEcoandBackup/Bitcoin_Node"; txindex = true; tor.proxy = true; diff --git a/modules/core/role-logic.nix b/modules/core/role-logic.nix index 9fa22f4..b7d0331 100755 --- a/modules/core/role-logic.nix +++ b/modules/core/role-logic.nix @@ -33,7 +33,6 @@ haven = lib.mkForce false; mempool = lib.mkForce false; element-calling = lib.mkForce false; - bitcoin-core = lib.mkForce false; "nwc-wallets" = lib.mkForce false; }; diff --git a/modules/core/roles.nix b/modules/core/roles.nix index bbf610b..b35080f 100755 --- a/modules/core/roles.nix +++ b/modules/core/roles.nix @@ -45,23 +45,19 @@ haven = lib.mkEnableOption "Haven NOSTR relay"; mempool = lib.mkEnableOption "Bitcoin Mempool Explorer"; element-calling = lib.mkEnableOption "Element Video and Audio Calling"; - bitcoin-core = lib.mkEnableOption "Bitcoin Core"; - "nwc-wallets" = lib.mkEnableOption "Lightning Wallet Connections"; - rdp = lib.mkEnableOption "Gnome Remote Desktop"; - sshd = lib.mkEnableOption "SSH remote access"; - - # Deprecated: BIP-110 is now built into mainline Bitcoin Knots and is the - # default node. This option is retained ONLY so that existing machines with - # `sovran_systemsOS.features.bip110 = lib.mkForce true;` left in their local - # custom.nix continue to evaluate. It has no effect and will be removed in a - # future release once the Hub has cleaned up old custom.nix files. - bip110 = lib.mkOption { + # Compatibility shim for Hub-managed settings from releases where Core + # was an optional replacement for the default node. Core is now always + # selected when the Bitcoin service is enabled. + bitcoin-core = lib.mkOption { type = lib.types.nullOr lib.types.bool; default = null; internal = true; visible = false; - description = "(Deprecated, no-op) BIP-110 is now built into Bitcoin Knots."; + description = "Deprecated no-op: Bitcoin Core is the default node implementation."; }; + "nwc-wallets" = lib.mkEnableOption "Lightning Wallet Connections"; + rdp = lib.mkEnableOption "Gnome Remote Desktop"; + sshd = lib.mkEnableOption "SSH remote access"; }; # ── Web exposure (controls Caddy vhosts) ────────────────── @@ -103,14 +99,4 @@ }; }; - config = lib.mkIf (config.sovran_systemsOS.features.bip110 != null) { - warnings = [ - '' - sovran_systemsOS.features.bip110 is deprecated and has no effect: - BIP-110 is now built into mainline Bitcoin Knots, which is the default node. - You can safely remove the `sovran_systemsOS.features.bip110` line from - /etc/nixos/custom.nix. The Sovran Hub will also remove it automatically. - '' - ]; - }; } diff --git a/modules/core/sovran-hub.nix b/modules/core/sovran-hub.nix index 79a5d80..dec3eb5 100644 --- a/modules/core/sovran-hub.nix +++ b/modules/core/sovran-hub.nix @@ -37,12 +37,9 @@ let { label = "How to Connect"; value = "1. Install an RDP client (e.g. Remmina, Microsoft Remote Desktop)\n2. Create a new RDP connection\n3. Enter the Address above as the host\n4. Enter the Username and Password above"; } ]; } ] - # ── Bitcoin Base (node implementations) ──────────────────── + # ── Bitcoin Base ──────────────────────────────────────────── ++ lib.optionals cfg.services.bitcoin [ - { name = "Bitcoin Knots + BIP110"; unit = "bitcoind.service"; type = "system"; icon = "bip110"; enabled = cfg.services.bitcoin && !cfg.features.bitcoin-core; category = "bitcoin-base"; credentials = [ - { label = "Tor Address — Access from anywhere via Tor Browser"; file = "/var/lib/tor/onion/bitcoind/hostname"; prefix = "http://"; } - ]; } - { name = "Bitcoin Core"; unit = "bitcoind.service"; type = "system"; icon = "bitcoin-core"; enabled = cfg.features.bitcoin-core; category = "bitcoin-base"; credentials = [ + { name = "Bitcoin Core"; unit = "bitcoind.service"; type = "system"; icon = "bitcoin-core"; enabled = cfg.services.bitcoin; category = "bitcoin-base"; credentials = [ { label = "Tor Address — Access from anywhere via Tor Browser"; file = "/var/lib/tor/onion/bitcoind/hostname"; prefix = "http://"; } ]; } ] @@ -132,7 +129,7 @@ let "caddy.service" = if pkgs ? caddy then pkgs.caddy.version else "2.8.4"; "tor.service" = if pkgs ? tor then pkgs.tor.version else "0.4.8.12"; "gnome-remote-desktop.service" = if pkgs ? gnome-remote-desktop then pkgs.gnome-remote-desktop.version else "46.0"; - "bitcoind.service" = if pkgs ? bitcoind-knots then pkgs.bitcoind-knots.version else (if pkgs ? bitcoind then pkgs.bitcoind.version else "27.1.0"); + "bitcoind.service" = if pkgs ? bitcoind then pkgs.bitcoind.version else "27.1.0"; "electrs.service" = if pkgs ? electrs then pkgs.electrs.version else "0.10.6"; "lnd.service" = if pkgs ? lnd then pkgs.lnd.version else "0.18.0"; # Keep the fallbacks aligned with the vendored packages used by the @@ -244,7 +241,7 @@ let # Stream output straight into $LOG (tee'd by the exec redirect above) so # the Hub UI shows live progress. Capturing the output in a variable # kept the log empty for the entire build+activation, which made long - # rebuilds (e.g. the Bitcoin Knots → Core switch) look like a hang. + # rebuilds can otherwise look like a hang. nixos-rebuild switch --flake /etc/nixos --print-build-logs \ --option connect-timeout 10 \ --option stalled-download-timeout 90 \ diff --git a/modules/modules.nix b/modules/modules.nix index 00fd5d2..5399d31 100755 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -35,7 +35,6 @@ ./nwc-wallets.nix ./element-calling.nix ./mempool.nix - ./bitcoin-core.nix ./rdp.nix ./sshd.nix ];