Merge pull request #430 from naturallaw777/chore/bitcoin-core-only
Replace Bitcoin Knots with Bitcoin Core
This commit is contained in:
+1
-2
@@ -10,7 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Fixed
|
### 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
|
- Sessions are now persisted to `/var/lib/secrets/hub-sessions.json` so the
|
||||||
browser login survives the Hub service restart that `nixos-rebuild switch`
|
browser login survives the Hub service restart that `nixos-rebuild switch`
|
||||||
performs during activation. Previously the in-memory session store was
|
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
|
- Integrated Sparrow Wallet, Bisq, and Bisq 2
|
||||||
- Comprehensive Sovran Hub for service management
|
- Comprehensive Sovran Hub for service management
|
||||||
- NixOS-based operating system with privacy and sovereignty focus
|
- 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
|
- Server + Desktop hybrid mode with Matrix, Nextcloud, VaultWarden, and other self-hosted services
|
||||||
- Automated installer with graphical GNOME desktop
|
- Automated installer with graphical GNOME desktop
|
||||||
- Tor integration and onion services for all major components
|
- Tor integration and onion services for all major components
|
||||||
|
|||||||
@@ -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
|
- **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
|
company holds user funds, and no exchange account stands between buyers and
|
||||||
sellers.
|
sellers.
|
||||||
- **Verify your own Bitcoin** with a full node: [Bitcoin
|
- **Verify your own Bitcoin** with a full node: [Bitcoin Core](https://bitcoin.org) and
|
||||||
Knots](https://bitcoinknots.org) and
|
|
||||||
[Electrs](https://github.com/romanz/electrs), so your wallets connect to
|
[Electrs](https://github.com/romanz/electrs), so your wallets connect to
|
||||||
*your* node instead of a stranger's.
|
*your* node instead of a stranger's.
|
||||||
- **Use Lightning** with [LND](https://github.com/lightningnetwork/lnd) and
|
- **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
|
### 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
|
- LND and Ride The Lightning, with [Alby Hub](https://albyhub.com) for Nostr
|
||||||
Wallet Connect (NWC) connections
|
Wallet Connect (NWC) connections
|
||||||
- BTCPay Server
|
- BTCPay Server
|
||||||
- Sparrow Wallet, Bisq, and Bisq 2, with automatic wallet-to-node connections
|
- Sparrow Wallet, Bisq, and Bisq 2, with automatic wallet-to-node connections
|
||||||
- Optional: a self-hosted [Mempool](https://github.com/mempool/mempool)
|
- 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.
|
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 |
|
| 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 |
|
| **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 |
|
| **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
|
**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` |
|
| Shared credentials | `modules/credentials.nix` |
|
||||||
| Bitcoin and Lightning stack | `modules/bitcoinecosystem.nix` |
|
| Bitcoin and Lightning stack | `modules/bitcoinecosystem.nix` |
|
||||||
| Automatic wallet-to-node connections | `modules/wallet-autoconnect.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/` |
|
| Alby Hub and Nostr Wallet Connect (NWC) on LND | `modules/nwc-wallets.nix`, `packages/albyhub/` |
|
||||||
| Matrix Synapse | `modules/synapse.nix` |
|
| Matrix Synapse | `modules/synapse.nix` |
|
||||||
| Optional Element audio and video calling via LiveKit | `modules/element-calling.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:
|
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)
|
- [Bitcoin Core](https://github.com/bitcoin/bitcoin)
|
||||||
- [Sparrow Wallet](https://github.com/sparrowwallet/sparrow)
|
- [Sparrow Wallet](https://github.com/sparrowwallet/sparrow)
|
||||||
- [Bisq](https://github.com/bisq-network/bisq)
|
- [Bisq](https://github.com/bisq-network/bisq)
|
||||||
|
|||||||
@@ -1,244 +0,0 @@
|
|||||||
<svg width="256" height="256" version="1.1" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<image width="256" height="256" image-rendering="optimizeQuality" preserveAspectRatio="none" xlink:href="data:image/png;base64,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
|
|
||||||
"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
@@ -149,7 +149,6 @@ SESSION_MAX_AGE = 86400 # 24 hours
|
|||||||
# Sessions are persisted here so logins survive a restart of the Hub service.
|
# Sessions are persisted here so logins survive a restart of the Hub service.
|
||||||
# nixos-rebuild switch restarts sovran-hub-web.service during activation (its
|
# nixos-rebuild switch restarts sovran-hub-web.service during activation (its
|
||||||
# unit definition changes with every feature toggle — e.g. the Bitcoin
|
# 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
|
# PATH). Without persistence the browser session dies mid-rebuild, the
|
||||||
# /api/rebuild/status polling starts receiving 401s and the rebuild modal
|
# /api/rebuild/status polling starts receiving 401s and the rebuild modal
|
||||||
# hangs forever showing "Applying changes…". The file lives in
|
# hangs forever showing "Applying changes…". The file lives in
|
||||||
@@ -318,18 +317,6 @@ FEATURE_REGISTRY = [
|
|||||||
"conflicts_with": [],
|
"conflicts_with": [],
|
||||||
"port_requirements": [],
|
"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",
|
"id": "sshd",
|
||||||
"name": "SSH Remote Access",
|
"name": "SSH Remote Access",
|
||||||
@@ -363,7 +350,7 @@ FEATURE_REGISTRY = [
|
|||||||
|
|
||||||
# Feature ids that have been removed/deprecated. The Hub must never write these
|
# 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).
|
# 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
|
# Map feature IDs to their systemd units in config.json
|
||||||
FEATURE_SERVICE_MAP = {
|
FEATURE_SERVICE_MAP = {
|
||||||
@@ -371,7 +358,6 @@ FEATURE_SERVICE_MAP = {
|
|||||||
"haven": "haven-relay.service",
|
"haven": "haven-relay.service",
|
||||||
"element-calling": "livekit.service",
|
"element-calling": "livekit.service",
|
||||||
"mempool": "mempool.service",
|
"mempool": "mempool.service",
|
||||||
"bitcoin-core": None,
|
|
||||||
"btcpay-web": "btcpayserver.service",
|
"btcpay-web": "btcpayserver.service",
|
||||||
"nwc-wallets": "albyhub.service",
|
"nwc-wallets": "albyhub.service",
|
||||||
"sshd": "sshd.service",
|
"sshd": "sshd.service",
|
||||||
@@ -426,9 +412,7 @@ SERVICE_DOMAIN_MAP: dict[str, str] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# For features that share a unit, disambiguate by icon field
|
# For features that share a unit, disambiguate by icon field
|
||||||
FEATURE_ICON_MAP = {
|
FEATURE_ICON_MAP: dict[str, str] = {}
|
||||||
"bitcoin-core": "bitcoin-core",
|
|
||||||
}
|
|
||||||
|
|
||||||
ROLE_LABELS = {
|
ROLE_LABELS = {
|
||||||
"server_plus_desktop": "Server + Desktop",
|
"server_plus_desktop": "Server + Desktop",
|
||||||
@@ -447,7 +431,7 @@ ROLE_CATEGORIES: dict[str, set[str] | None] = {
|
|||||||
ROLE_FEATURES: dict[str, set[str] | None] = {
|
ROLE_FEATURES: dict[str, set[str] | None] = {
|
||||||
"server_plus_desktop": None,
|
"server_plus_desktop": None,
|
||||||
"desktop": {"rdp", "sshd"},
|
"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] = {
|
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
|
return False # Default off in Node role; only on via explicit hub toggle
|
||||||
unit = FEATURE_SERVICE_MAP.get(feature_id)
|
unit = FEATURE_SERVICE_MAP.get(feature_id)
|
||||||
if unit is None:
|
if unit is None:
|
||||||
return None # bitcoin-core — can't determine from config
|
return None
|
||||||
cfg = load_config()
|
cfg = load_config()
|
||||||
for svc in cfg.get("services", []):
|
for svc in cfg.get("services", []):
|
||||||
if svc.get("unit") == unit:
|
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: tuple[float, dict | None] = (0.0, None)
|
||||||
_BTC_SYNC_CACHE_TTL = 5 # seconds
|
_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
|
_BTC_VERSION_CACHE_TTL = 60 # seconds — version doesn't change at runtime
|
||||||
|
|
||||||
# Cache for ``bitcoind --version`` output (available even before RPC is ready)
|
# Cache for ``bitcoind --version`` output (available even before RPC is ready)
|
||||||
_btcd_version_cache: tuple[float, str | None] = (0.0, None)
|
_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) ─────────
|
# ── Generic service version detection (NixOS store path) ─────────
|
||||||
@@ -2963,213 +2937,12 @@ def _get_service_version(unit: str) -> str | None:
|
|||||||
return version
|
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:
|
def _get_bitcoind_version() -> str | None:
|
||||||
"""Run ``bitcoind --version`` and return the raw version string, or None on error.
|
"""Run ``bitcoind --version`` and return the raw version string, or None on error.
|
||||||
|
|
||||||
Parses the first output line to extract the token after "version ".
|
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.).
|
Works regardless of whether the RPC server is ready (IBD, warmup, etc.).
|
||||||
Results are cached for 60 seconds (_BTC_VERSION_CACHE_TTL).
|
Results are cached for 60 seconds (_BTC_VERSION_CACHE_TTL).
|
||||||
"""
|
"""
|
||||||
@@ -3200,17 +2973,9 @@ def _get_bitcoind_version() -> str | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _format_bitcoin_version(raw_version: str, icon: str = "") -> str:
|
def _format_bitcoin_version(raw_version: str) -> str:
|
||||||
"""Format a raw version string from ``bitcoind --version`` for tile display.
|
"""Format a raw version string from ``bitcoind --version`` for display."""
|
||||||
|
return raw_version
|
||||||
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 _get_bitcoin_sync_info() -> dict | None:
|
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")
|
@app.get("/api/services")
|
||||||
async def api_services():
|
async def api_services():
|
||||||
started_at = time.monotonic()
|
started_at = time.monotonic()
|
||||||
@@ -3371,39 +3123,27 @@ async def api_services():
|
|||||||
dns_states_future = asyncio.gather(
|
dns_states_future = asyncio.gather(
|
||||||
*(resolve_domain(domain) for domain in sorted(domain_names))
|
*(resolve_domain(domain) for domain in sorted(domain_names))
|
||||||
)
|
)
|
||||||
# Bitcoin sync and BIP-110 are supplementary tile metadata. Fetch each
|
# Bitcoin sync is supplementary tile metadata. Fetch it once alongside
|
||||||
# once, concurrently with the other diagnostics, instead of doing duplicate
|
# the other diagnostics instead of duplicating RPC calls per tile.
|
||||||
# RPC calls inside both bitcoind tile coroutines.
|
|
||||||
has_enabled_bitcoin = any(
|
has_enabled_bitcoin = any(
|
||||||
entry.get("unit") == "bitcoind.service" and enabled
|
entry.get("unit") == "bitcoind.service" and enabled
|
||||||
for entry, enabled in effective_entries
|
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 = (
|
bitcoin_sync_future = (
|
||||||
loop.run_in_executor(None, _get_bitcoin_sync_info)
|
loop.run_in_executor(None, _get_bitcoin_sync_info)
|
||||||
if has_enabled_bitcoin
|
if has_enabled_bitcoin
|
||||||
else asyncio.sleep(0, result=None)
|
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,
|
active_states,
|
||||||
port_states,
|
port_states,
|
||||||
dns_states,
|
dns_states,
|
||||||
bitcoin_sync_info,
|
bitcoin_sync_info,
|
||||||
bip110_status,
|
|
||||||
) = await asyncio.gather(
|
) = await asyncio.gather(
|
||||||
active_states_future,
|
active_states_future,
|
||||||
port_states_future,
|
port_states_future,
|
||||||
dns_states_future,
|
dns_states_future,
|
||||||
bitcoin_sync_future,
|
bitcoin_sync_future,
|
||||||
bip110_future,
|
|
||||||
)
|
)
|
||||||
listening_ports, firewall_ports = port_states
|
listening_ports, firewall_ports = port_states
|
||||||
resolved_domains = dict(dns_states)
|
resolved_domains = dict(dns_states)
|
||||||
@@ -3559,11 +3299,9 @@ async def api_services():
|
|||||||
if unit == "bitcoind.service" and enabled:
|
if unit == "bitcoind.service" and enabled:
|
||||||
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
||||||
if raw_ver is not None:
|
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["bitcoin_version"] = btc_ver # backwards compat
|
||||||
service_data["version"] = btc_ver
|
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) ──────────
|
# ── Generic version for all services (Nix store path) ──────────
|
||||||
if enabled and unit and "version" not in service_data:
|
if enabled and unit and "version" not in service_data:
|
||||||
ver = await loop.run_in_executor(None, _get_service_version, unit)
|
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()
|
loop = asyncio.get_event_loop()
|
||||||
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
raw_ver = await loop.run_in_executor(None, _get_bitcoind_version)
|
||||||
if raw_ver is not None:
|
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["bitcoin_version"] = btc_ver # backwards compat
|
||||||
service_detail["version"] = btc_ver
|
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) ──────────
|
# ── Generic version for all services (Nix store path) ──────────
|
||||||
if enabled and unit and "version" not in service_detail:
|
if enabled and unit and "version" not in service_detail:
|
||||||
ver = await loop.run_in_executor(None, _get_service_version, unit)
|
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")
|
@app.on_event("startup")
|
||||||
async def _startup_migrate_deprecated_features():
|
async def _startup_migrate_deprecated_features():
|
||||||
"""Strip deprecated feature lines (e.g. bip110) from the Hub Managed section
|
"""Strip deprecated feature lines from the Hub Managed section of custom.nix."""
|
||||||
of custom.nix so they are never re-written and do not cause stale warnings."""
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
await loop.run_in_executor(None, _migrate_strip_deprecated_features)
|
await loop.run_in_executor(None, _migrate_strip_deprecated_features)
|
||||||
|
|
||||||
|
|||||||
@@ -178,68 +178,6 @@
|
|||||||
white-space: nowrap;
|
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 ───────────────────────────────── */
|
/* ── Service detail modal sections ───────────────────────────────── */
|
||||||
|
|
||||||
|
|||||||
@@ -403,10 +403,7 @@ function handleFeatureToggle(feat, newEnabled) {
|
|||||||
openPortRequirementsModal(feat.name, ports, proceedAfterPortCheck);
|
openPortRequirementsModal(feat.name, ports, proceedAfterPortCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feat.id === "bitcoin-core") {
|
if (conflictNames.length > 0) {
|
||||||
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) {
|
|
||||||
openFeatureConfirm("This will disable " + conflictNames.join(", ") + ". Continue?", proceedAfterConflictCheck);
|
openFeatureConfirm("This will disable " + conflictNames.join(", ") + ". Continue?", proceedAfterConflictCheck);
|
||||||
} else {
|
} else {
|
||||||
proceedAfterConflictCheck();
|
proceedAfterConflictCheck();
|
||||||
|
|||||||
@@ -133,17 +133,3 @@ async function apiFetch(path, options) {
|
|||||||
}
|
}
|
||||||
return res.json();
|
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)' }
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -704,20 +704,6 @@ async function openServiceDetailModal(unit, name, icon) {
|
|||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>');
|
'</div>');
|
||||||
|
|
||||||
// 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 ? ' <span class="bip110-source-label">(source: ' + escHtml(bip110.source) + ')</span>' : '';
|
|
||||||
html += '<div class="svc-detail-section">' +
|
|
||||||
'<div class="svc-detail-section-title">BIP-110 Deployment Status</div>' +
|
|
||||||
'<div class="bip110-status-row">' +
|
|
||||||
'<span class="tile-bip110-badge ' + bip110Cfg.cls + '" title="' + escHtml(bip110Cfg.title) + '">' + escHtml(bip110Cfg.label) + '</span>' +
|
|
||||||
bip110Source +
|
|
||||||
'</div>' +
|
|
||||||
'</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section C: Domain diagnostics (domain services)
|
// Section C: Domain diagnostics (domain services)
|
||||||
if (data.needs_domain) {
|
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";
|
var addonBtnCls = feat.enabled ? "btn btn-close-modal" : "btn btn-primary";
|
||||||
|
|
||||||
// Section title: use a more specific label for mutually-exclusive Bitcoin node features
|
// Section title: use a more specific label for mutually-exclusive Bitcoin node features
|
||||||
var addonSectionTitle = (feat.id === "bitcoin-core")
|
var addonSectionTitle = "\uD83D\uDD27 Addon Feature";
|
||||||
? "\u20BF Bitcoin Node Selection"
|
|
||||||
: "\uD83D\uDD27 Addon Feature";
|
|
||||||
|
|
||||||
// Description: prefer the feature's own description over a generic fallback
|
// Description: prefer the feature's own description over a generic fallback
|
||||||
var addonDesc = feat.description
|
var addonDesc = feat.description
|
||||||
|
|||||||
@@ -4,14 +4,6 @@
|
|||||||
// Keyed by tileId: { progress: float, timestamp: ms }
|
// Keyed by tileId: { progress: float, timestamp: ms }
|
||||||
var _btcSyncPrev = {};
|
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 '<div class="tile-bip110-badge ' + cfg.cls + '" title="' + escHtml(cfg.title) + '">' + escHtml(cfg.label) + '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function _firstElementFromHtml(html) {
|
function _firstElementFromHtml(html) {
|
||||||
var tmp = document.createElement("div");
|
var tmp = document.createElement("div");
|
||||||
@@ -175,8 +167,7 @@ function buildTile(svc) {
|
|||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bip110Badge = (svc.icon === 'bip110') ? _renderBip110Badge(svc.bip110) : '';
|
tile.innerHTML = '<img class="tile-icon" src="/static/icons/' + escHtml(svc.icon) + '.svg" alt="' + escHtml(svc.name) + '" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'flex\'"><div class="tile-icon-fallback" style="display:none">?</div><div class="tile-name">' + escHtml(svc.name) + '</div><div class="tile-status"><span class="status-dot ' + sc + '"></span><span class="status-text">' + st + '</span></div>';
|
||||||
tile.innerHTML = '<img class="tile-icon" src="/static/icons/' + escHtml(svc.icon) + '.svg" alt="' + escHtml(svc.name) + '" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'flex\'"><div class="tile-icon-fallback" style="display:none">?</div><div class="tile-name">' + escHtml(svc.name) + '</div>' + bip110Badge + '<div class="tile-status"><span class="status-dot ' + sc + '"></span><span class="status-text">' + st + '</span></div>';
|
|
||||||
|
|
||||||
tile.style.cursor = "pointer";
|
tile.style.cursor = "pointer";
|
||||||
tile.addEventListener("click", function() {
|
tile.addEventListener("click", function() {
|
||||||
@@ -244,23 +235,6 @@ function updateTiles(services) {
|
|||||||
var text = tile.querySelector(".status-text");
|
var text = tile.querySelector(".status-text");
|
||||||
if (dot) dot.className = "status-dot " + sc;
|
if (dot) dot.className = "status-dot " + sc;
|
||||||
if (text) text.textContent = st;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -62,11 +62,6 @@ let
|
|||||||
description = ''
|
description = ''
|
||||||
The package providing bitcoind binaries.
|
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 {
|
extraConfig = mkOption {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ lib.mkIf config.sovran_systemsOS.services.bitcoin {
|
|||||||
|
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.bitcoind-knots;
|
package = pkgs.bitcoind;
|
||||||
dataDir = "/run/media/Second_Drive/BTCEcoandBackup/Bitcoin_Node";
|
dataDir = "/run/media/Second_Drive/BTCEcoandBackup/Bitcoin_Node";
|
||||||
txindex = true;
|
txindex = true;
|
||||||
tor.proxy = true;
|
tor.proxy = true;
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
haven = lib.mkForce false;
|
haven = lib.mkForce false;
|
||||||
mempool = lib.mkForce false;
|
mempool = lib.mkForce false;
|
||||||
element-calling = lib.mkForce false;
|
element-calling = lib.mkForce false;
|
||||||
bitcoin-core = lib.mkForce false;
|
|
||||||
"nwc-wallets" = lib.mkForce false;
|
"nwc-wallets" = lib.mkForce false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+8
-22
@@ -45,23 +45,19 @@
|
|||||||
haven = lib.mkEnableOption "Haven NOSTR relay";
|
haven = lib.mkEnableOption "Haven NOSTR relay";
|
||||||
mempool = lib.mkEnableOption "Bitcoin Mempool Explorer";
|
mempool = lib.mkEnableOption "Bitcoin Mempool Explorer";
|
||||||
element-calling = lib.mkEnableOption "Element Video and Audio Calling";
|
element-calling = lib.mkEnableOption "Element Video and Audio Calling";
|
||||||
bitcoin-core = lib.mkEnableOption "Bitcoin Core";
|
# Compatibility shim for Hub-managed settings from releases where Core
|
||||||
"nwc-wallets" = lib.mkEnableOption "Lightning Wallet Connections";
|
# was an optional replacement for the default node. Core is now always
|
||||||
rdp = lib.mkEnableOption "Gnome Remote Desktop";
|
# selected when the Bitcoin service is enabled.
|
||||||
sshd = lib.mkEnableOption "SSH remote access";
|
bitcoin-core = lib.mkOption {
|
||||||
|
|
||||||
# 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 {
|
|
||||||
type = lib.types.nullOr lib.types.bool;
|
type = lib.types.nullOr lib.types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
internal = true;
|
internal = true;
|
||||||
visible = false;
|
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) ──────────────────
|
# ── 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.
|
|
||||||
''
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"; }
|
{ 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 [
|
++ 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 = [
|
{ 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://"; }
|
|
||||||
]; }
|
|
||||||
{ name = "Bitcoin Core"; unit = "bitcoind.service"; type = "system"; icon = "bitcoin-core"; enabled = 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://"; }
|
{ 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";
|
"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";
|
"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";
|
"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";
|
"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";
|
"lnd.service" = if pkgs ? lnd then pkgs.lnd.version else "0.18.0";
|
||||||
# Keep the fallbacks aligned with the vendored packages used by the
|
# 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
|
# 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
|
# the Hub UI shows live progress. Capturing the output in a variable
|
||||||
# kept the log empty for the entire build+activation, which made long
|
# 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 \
|
nixos-rebuild switch --flake /etc/nixos --print-build-logs \
|
||||||
--option connect-timeout 10 \
|
--option connect-timeout 10 \
|
||||||
--option stalled-download-timeout 90 \
|
--option stalled-download-timeout 90 \
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
./nwc-wallets.nix
|
./nwc-wallets.nix
|
||||||
./element-calling.nix
|
./element-calling.nix
|
||||||
./mempool.nix
|
./mempool.nix
|
||||||
./bitcoin-core.nix
|
|
||||||
./rdp.nix
|
./rdp.nix
|
||||||
./sshd.nix
|
./sshd.nix
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user