Skip to content

SV2 pool identity: persistent authority key for miner pinning (+ stats correctness fixes) - #31

Merged
cbyam merged 2 commits into
mainfrom
feat/sv2-authority-pinning
Jul 2, 2026
Merged

SV2 pool identity: persistent authority key for miner pinning (+ stats correctness fixes)#31
cbyam merged 2 commits into
mainfrom
feat/sv2-authority-pinning

Conversation

@cbyam

@cbyam cbyam commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

By default SV2 connects encrypted but the pool has no stable identity to verify: the Noise authority key was generated fresh per process, so there was nothing a miner could pin. This makes the authority key persistent and easy to pin, closing the pool-side half of the story that bitaxeorg/ESP-Miner#1796 and shufps/ESP-Miner-NerdQAxePlus#656 close on the miner side.

  • The authority key persists in [sv2] authority_key_file (default sv2-authority.key), created on first start with owner-only permissions, the same pattern as bitcoind's .cookie.
  • The base58check public key (SRI key-utils format) is logged at startup, shown in the dashboard Connect modal with a copy button, and returned by GET /api/info as sv2_authority_pubkey.
  • persist_authority_key = false opts back into a fresh key per process. cert_validity_secs makes the signed certificate window configurable (default one year).
  • All new config keys default sensibly; existing config files load unchanged. Miners that do not pin connect exactly as before.

Upgrade note (why this is 0.6.0)

With SV2 enabled the pool now creates the key file at boot and fails loudly if it cannot. Deployments with a read-only working directory (the shipped systemd unit uses ProtectSystem=strict) must set authority_key_file to a writable path such as /var/lib/solo-pool-rs/sv2-authority.key, or set persist_authority_key = false. Comments added to the unit file and docker-compose.yml; per the pre-1.0 convention (breaking bumps minor) this ships as 0.6.0.

Also in this PR

  • Dashboard Copy buttons work over plain HTTP. navigator.clipboard only exists in secure contexts; the old code showed "Copied" without copying on the LAN dashboard. Now falls back to document.execCommand('copy'), with an honest "Copy manually" state if that fails too.
  • Duplicate-share tracking hardened. Shares are recorded for dedup only after validation passes (invalid submissions could previously occupy slots and cause later identical valid submits to be misreported as duplicate), and the per-session set clears on clean-job broadcasts, scoping replay protection to live jobs instead of FIFO eviction.
  • Monotonic best-value stats. Pool best-share/best-hashrate SQLite UPDATEs carry ?1 > ... guards (matching the per-worker variant) and the in-memory best-hashrate update is a CAS loop.
  • Retrier-accepted blocks credited to the dashboard. A block accepted by the background submit retrier now updates the dashboard block count and last-block panel, not just Prometheus.

Testing

  • cargo fmt --check, clippy --all-targets --all-features (no warnings), cargo test (62 passed), cargo build --release all green.
  • New tests drive real Noise handshakes against a pinning noise_sv2::Initiator: correct key accepted, wrong authority key rejected, certificate outside its validity window rejected, no-pin still connects; plus key-file round-trip/permissions and dedup lifecycle tests.
  • Verified on hardware against a NerdQAxe++ (AxeOS SV2): pinned key verifies ("Server certificate verified OK") and mines; a wrong-but-valid-format key is rejected before a channel opens (pool sees ~200 ms connect/disconnect loops, zero shares).

The Noise authority key now persists across restarts in
[sv2] authority_key_file (created on first start with owner-only
permissions, the same pattern as bitcoind's .cookie), so the pool keeps
a stable identity that miners can pin. The base58check public key (SRI
key-utils format) is logged at startup, shown in the dashboard Connect
modal with a copy button, and returned by GET /api/info as
sv2_authority_pubkey. persist_authority_key = false opts back into a
fresh key per process; cert_validity_secs makes the certificate window
configurable (default one year).

Upgrade note: with SV2 enabled the pool now fails at boot if it cannot
create the key file. Deployments with a read-only working directory
(e.g. the shipped systemd unit with ProtectSystem=strict) must point
authority_key_file at a writable path; comments added to the unit file
and docker-compose.yml.

Verified on hardware against a NerdQAxe++ (AxeOS SV2): pinned key
verifies and mines, wrong authority key is rejected before a channel
opens. New tests drive real handshakes against a pinning
noise_sv2::Initiator (correct/wrong/expired/no-pin) plus key-file
round-trip and permission checks.

Also in this change:

- Dashboard Copy buttons now work over plain HTTP: fall back to
  document.execCommand('copy') outside secure contexts instead of
  showing "Copied" without copying.
- Duplicate-share tracking records a share only after validation passes
  and clears on clean-job broadcasts, so invalid submissions cannot
  occupy dedup slots and replay protection is scoped to live jobs.
- Pool best-share/best-hashrate writes are monotonic (SQL "?1 >" guards
  plus a CAS on the in-memory best hashrate).
- Blocks accepted by the background submit retrier now update dashboard
  stats, not just Prometheus.
Comment thread src/mining/validator.rs Fixed
Comment thread src/mining/validator.rs Fixed
Comment thread src/mining/validator.rs Fixed
CodeQL's hard-coded-cryptographic-value rule reads the mining header
nonce as a cryptographic nonce and flags any constant flowing into it
(three critical alerts on PR #31, all in test data). Generate the test
keys from a range like the FIFO-eviction test already did, which the
rule accepts.
@cbyam
cbyam merged commit ebfab51 into main Jul 2, 2026
5 checks passed
@cbyam
cbyam deleted the feat/sv2-authority-pinning branch July 2, 2026 17:21
@cbyam cbyam mentioned this pull request Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants