diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 07c9014..789489f 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -35,10 +35,14 @@ jobs: run: | envsubst < gridlabs-gridpool/templates/boot_portal_config.json.template > /tmp/config.json jq empty /tmp/config.json + test "$(jq -r '.native_sv2_enabled' /tmp/config.json)" = "true" + test "$(jq -r '.native_sv2_public_port' /tmp/config.json)" = "34265" + test "$(jq -r '.enable_admin_api' /tmp/config.json)" = "false" test "$(jq -r .pool_payout_script /tmp/config.json)" = "" - name: Verify UI-driven payout lifecycle run: | ! grep -q 'env_file' gridlabs-gridpool/docker-compose.yml + grep -q 'APP_HOST: gridpool$' gridlabs-gridpool/docker-compose.yml test "$(grep -Fc '${APP_DATA_DIR}/templates:/templates:ro' gridlabs-gridpool/docker-compose.yml)" = "3" ! grep -Fq '${GRIDPOOL_PAYOUT_ADDRESS:-}' gridlabs-gridpool/templates/init.sh grep -q 'boot_portal_config.local.json' gridlabs-gridpool/templates/gridpool-entrypoint.sh @@ -64,8 +68,8 @@ jobs: fail-fast: false matrix: image: - - ghcr.io/gridlabs-science/boot-protocol@sha256:8672c835b14f8fcad8a358e5b80ae945d6973b5039c706437b3b1c4bdff6f5d5 - - ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e + - ghcr.io/gridlabs-science/boot-protocol@sha256:c83601e3fd051b834b02376dbd7827652fa96826b9454050c5d2ae933f9475bc + - ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:894b04939da127188d97dd53aaf5e3a6514de959c827a6ba34161ed5a2fc6fb0 steps: - uses: aquasecurity/trivy-action@v0.36.0 with: diff --git a/README.md b/README.md index 924296a..e61cbca 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,25 @@ Point a native SV2 miner at: stratum2+noise://UMBREL_LAN_IP:34265 ``` +The GridPool dashboard also shows this endpoint under **Connect miner**. The +hostname is inferred from the browser when the package does not have a public +hostname configured, so use the Umbrel device's LAN hostname or IP if the +displayed browser hostname is not reachable from the miner. + +The dashboard also displays the pool's persisted Noise authority public key. +AxeOS miners require this value in **Pool > Show Advanced Options > SV2 +Authority Pubkey**. The public key identifies the server and is safe to copy; +the corresponding private key remains inside the package data directory. + The per-channel SV2 username may be a valid mainnet payout address. If it is a worker label instead, the package payout address is used. +The appliance disables GridPool's destructive administrative API and does not +provision an operator password. Because Umbrel's authenticated app proxy is the +access boundary, the dashboard displays read-only operator diagnostics directly +and hides the operator-unlock control. Advanced operators may explicitly enable +the write API and set a strong key in local configuration. + ## Persistence and backup `gridlabs-gridpool/data` contains node identity, consensus state, the local adapter diff --git a/gridlabs-gridpool/docker-compose.yml b/gridlabs-gridpool/docker-compose.yml index 9e3490e..aa05914 100644 --- a/gridlabs-gridpool/docker-compose.yml +++ b/gridlabs-gridpool/docker-compose.yml @@ -1,14 +1,22 @@ services: app_proxy: environment: - APP_HOST: gridlabs-gridpool_gridpool_1 + APP_HOST: gridpool APP_PORT: 5000 init: - image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e + image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:894b04939da127188d97dd53aaf5e3a6514de959c827a6ba34161ed5a2fc6fb0 user: "0:0" - entrypoint: ["/bin/sh", "/templates/init.sh"] + entrypoint: + - /bin/sh + - -c + - | + /bin/sh /templates/init.sh + sed -n 's/^authority_public_key=/GRIDPOOL_NATIVE_SV2_AUTHORITY_PUBLIC_KEY=/p' /data/sv2/authority.env > /data/shared/sv2-public.env + test -s /data/shared/sv2-public.env + chmod 644 /data/shared/sv2-public.env environment: + GRIDPOOL_PACKAGE_VERSION: "0.2.2-beta.8" APP_BITCOIN_NODE_IP: ${APP_BITCOIN_NODE_IP} APP_BITCOIN_RPC_PORT: ${APP_BITCOIN_RPC_PORT} APP_BITCOIN_RPC_USER: ${APP_BITCOIN_RPC_USER} @@ -20,15 +28,23 @@ services: - ${APP_DATA_DIR}/templates:/templates:ro gridpool: - image: ghcr.io/gridlabs-science/boot-protocol@sha256:8672c835b14f8fcad8a358e5b80ae945d6973b5039c706437b3b1c4bdff6f5d5 + image: ghcr.io/gridlabs-science/boot-protocol@sha256:c83601e3fd051b834b02376dbd7827652fa96826b9454050c5d2ae933f9475bc depends_on: init: condition: service_completed_successfully - entrypoint: ["/bin/sh", "/templates/gridpool-entrypoint.sh"] + entrypoint: + - /bin/sh + - -c + - | + set -a + . /shared/sv2-public.env + set +a + exec /bin/sh /templates/gridpool-entrypoint.sh restart: unless-stopped stop_grace_period: 30s environment: BOOT_PORTAL_LOCAL_CONFIG_PATH: /shared/boot_portal_config.local.json + GRIDPOOL_TRUSTED_PRIVATE_DASHBOARD_ENABLED: "true" volumes: - ${APP_DATA_DIR}/data/gridpool:/data - ${APP_DATA_DIR}/data/shared:/shared @@ -43,7 +59,7 @@ services: retries: 4 sv2: - image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:3de54e9c51953d2b5089ae90a25b9a0fa046c18c4ae0139b768b77a4cf0ed50e + image: ghcr.io/gridlabs-science/gridpool-sv2-pool@sha256:894b04939da127188d97dd53aaf5e3a6514de959c827a6ba34161ed5a2fc6fb0 depends_on: init: condition: service_completed_successfully diff --git a/gridlabs-gridpool/templates/boot_portal_config.json.template b/gridlabs-gridpool/templates/boot_portal_config.json.template index 572bb37..5310d5e 100644 --- a/gridlabs-gridpool/templates/boot_portal_config.json.template +++ b/gridlabs-gridpool/templates/boot_portal_config.json.template @@ -10,6 +10,7 @@ "bitcoin_network": "mainnet", "enable_web_ui": true, "enable_legacy_ui": false, + "restart_after_setup": true, "boot_network_id": "mainnet-beta", "boot_protocol_version": 22, "v22_activation_block_height": 959500, @@ -28,5 +29,10 @@ "work_set_reserve_multiplier": 3, "local_adapter_token_file": "/shared/local-adapter.token", "local_sv2_api_url": "http://sv2:34290/api/v1/global", - "enable_admin_api": false + "native_sv2_enabled": true, + "native_sv2_public_host": "", + "native_sv2_public_port": 34265, + "native_sv2_authority_public_key": "${authority_public_key}", + "enable_admin_api": false, + "trusted_private_dashboard_enabled": true } diff --git a/gridlabs-gridpool/templates/gridpool-entrypoint.sh b/gridlabs-gridpool/templates/gridpool-entrypoint.sh index 4da4749..bd94795 100755 --- a/gridlabs-gridpool/templates/gridpool-entrypoint.sh +++ b/gridlabs-gridpool/templates/gridpool-entrypoint.sh @@ -3,6 +3,12 @@ set -eu setup_override=/shared/boot_portal_config.local.json +if [ -s /shared/sv2-public.env ]; then + set -a + . /shared/sv2-public.env + set +a +fi + setup_is_complete() { [ -s "${setup_override}" ] && grep -q '"setup_completed"[[:space:]]*:[[:space:]]*true' "${setup_override}" && diff --git a/gridlabs-gridpool/templates/init.sh b/gridlabs-gridpool/templates/init.sh index 21d6858..bd6e9a6 100755 --- a/gridlabs-gridpool/templates/init.sh +++ b/gridlabs-gridpool/templates/init.sh @@ -14,6 +14,14 @@ if [ ! -s /data/sv2/authority.env ]; then /app/pool_sv2 --generate-authority-keypair > /data/sv2/authority.env fi +authority_public_key="$(sed -n 's/^authority_public_key=//p' /data/sv2/authority.env | head -n 1)" +if [ -z "${authority_public_key}" ]; then + echo "Native SV2 authority public key is missing" >&2 + exit 1 +fi +export authority_public_key +printf 'GRIDPOOL_NATIVE_SV2_AUTHORITY_PUBLIC_KEY=%s\n' "${authority_public_key}" > /data/shared/sv2-public.env + export BITCOIN_RPC_URL="http://${APP_BITCOIN_NODE_IP}:${APP_BITCOIN_RPC_PORT}" export BITCOIN_ZMQ_HASHBLOCK="tcp://${APP_BITCOIN_NODE_IP}:${APP_BITCOIN_ZMQ_HASHBLOCK_PORT}" export BITCOIN_ZMQ_RAWBLOCK="tcp://${APP_BITCOIN_NODE_IP}:${APP_BITCOIN_ZMQ_RAWBLOCK_PORT}" @@ -22,4 +30,5 @@ rm -f /data/sv2/pool-config.toml echo "GridPool payout address will be configured through the in-app setup page." chmod 600 /data/gridpool/boot_portal_config.json /data/sv2/authority.env /data/shared/local-adapter.token +chmod 600 /data/shared/sv2-public.env chown -R 1000:1000 /data/gridpool /data/sv2 /data/shared diff --git a/gridlabs-gridpool/umbrel-app.yml b/gridlabs-gridpool/umbrel-app.yml index c533dd1..c8a7e05 100644 --- a/gridlabs-gridpool/umbrel-app.yml +++ b/gridlabs-gridpool/umbrel-app.yml @@ -3,7 +3,7 @@ id: gridlabs-gridpool implements: [] category: bitcoin name: GridPool -version: "0.2.2-beta.2" +version: "0.2.2-beta.8" icon: https://raw.githubusercontent.com/gridlabs-science/gridpool-umbrel/main/gridlabs-gridpool/icon.svg tagline: Sovereign, non-custodial pooled mining description: >- @@ -17,10 +17,12 @@ support: https://github.com/gridlabs-science/gridpool-umbrel/issues dependencies: - bitcoin port: 5010 -path: "" +path: "setup" defaultUsername: "" defaultPassword: "" releaseNotes: >- - Early beta with V2.2 security hardening, native SV2 mining, attached-node - safety checks, authenticated UDP relay, and digest-pinned images. + Early beta with explicit setup completion, complete native SV2 connection + details including the Noise authority key, private appliance diagnostics, + mature-network bootstrap, V2.2 security hardening, and refreshed SV2 runtime + OS security libraries with the mining binary unchanged. gallery: [] diff --git a/scripts/verify-package.sh b/scripts/verify-package.sh index 2034765..a244ff9 100755 --- a/scripts/verify-package.sh +++ b/scripts/verify-package.sh @@ -7,6 +7,7 @@ template="gridlabs-gridpool/templates/boot_portal_config.json.template" for script in gridlabs-gridpool/templates/*.sh; do sh -n "$script"; done ruby -e 'require "yaml"; YAML.load_file(ARGV[0])' "$compose" ruby -e 'require "yaml"; YAML.load_file(ARGV[0])' gridlabs-gridpool/umbrel-app.yml +package_version="$(ruby -e 'require "yaml"; puts YAML.load_file(ARGV[0]).fetch("version")' gridlabs-gridpool/umbrel-app.yml)" references="$(grep -oE 'ghcr\.io/[^ @]+@sha256:[0-9a-f]{64}' "$compose" | sort -u)" [[ "$(printf '%s\n' "$references" | sed '/^$/d' | wc -l)" -eq 2 ]] @@ -14,6 +15,14 @@ references="$(grep -oE 'ghcr\.io/[^ @]+@sha256:[0-9a-f]{64}' "$compose" | sort - grep -q '"enable_legacy_ui": false' "$template" grep -q '"enable_admin_api": false' "$template" +grep -q '"trusted_private_dashboard_enabled": true' "$template" +grep -q 'GRIDPOOL_TRUSTED_PRIVATE_DASHBOARD_ENABLED: "true"' "$compose" +grep -q 'GRIDPOOL_NATIVE_SV2_AUTHORITY_PUBLIC_KEY' gridlabs-gridpool/templates/init.sh +grep -q '/shared/sv2-public.env' gridlabs-gridpool/templates/gridpool-entrypoint.sh +grep -q 'GRIDPOOL_NATIVE_SV2_AUTHORITY_PUBLIC_KEY=' "$compose" +grep -q '. /shared/sv2-public.env' "$compose" +grep -q 'native_sv2_authority_public_key' "$template" +grep -q "GRIDPOOL_PACKAGE_VERSION: \"${package_version}\"" "$compose" ! grep -q 'env_file' "$compose" ! grep -Eq '(^|[[:space:]])(8332|28332|28333|34290|5000):' "$compose" grep -q '34265:34265/tcp' "$compose"