Skip to content

v2.3.9

Choose a tag to compare

@warioishere warioishere released this 02 Oct 20:59
· 24 commits to main since this release

Payouts: a found block books what its own coinbase paid, in every mode

  • Group-Solo books a found block from its decoded coinbase alone. Builds no longer write a weight snapshot, so every build is bookable; a block is booked only when the pool built its coinbase, otherwise the round stays untouched.
  • Blockparty blocks now wait for their confirmations and settle through the confirmation watcher like PPLNS and Group-Solo, so an orphaned Blockparty block books nothing.
  • A Blockparty party is frozen once it is ready: its coinbase already pays the roster, so changing splits, removing a member or creating a join link is refused with not-editable, as it already was for active parties. The split booked for a block is therefore the one the block paid.
  • When a Blockparty split cannot be built, the admin is served no job. Previously the admin fell back to a solo coinbase that paid the whole block to the admin and nothing to the members.
  • PPLNS and Group-Solo builds share one result type and one conversion into coinbase outputs, and the PPLNS settlement snapshot now lives in the PPLNS engine, its only reader.

Payouts: a new share source no longer pays one miner the whole block for 30 s

  • The coinbase builders cache each build for 30 s, and on the front nothing invalidates that cache when a share lands, because shares are recorded by the payout process. A build made while the share source was empty therefore kept paying the asking miner the whole block for up to 30 s after other miners' shares had arrived: Group-Solo cached the bootstrap distribution itself, PPLNS cached the empty window it was built from. An empty share source is no longer cached in either mode, so the first share reaches the next job.

Block reconcile: no false alarm for blocks awaiting confirmation

  • A block parked for its confirmations has no payout rows yet, so a reconcile pass shortly after the payout process restarted reported it as "registered but no payout was ever booked". Parked blocks are now held back and checked again on the next pass, so a booking that later fails is still reported. A block the pool never registered is still always reported.

Stratum V2

  • A rejected share is weighted with its channel's current difficulty. It was weighted with the difficulty from the last channel open, which vardiff never updated, so SV2 reject charts and the Group-Solo reject lane carried a stale value. The stale per-session difficulty is gone.
  • A bad-extranonce-size reject is refused before anything is hashed, so it no longer counts as evidence of a too-hard target for vardiff, matching the SV1 pre-hash rejects.
  • The Standard and Extended submit handlers, the job broadcast for grouped and ungrouped channels and the PPLNS stream handling of the SV1 and SV2 servers each share one implementation instead of two copies.

Stratum V1

  • Shutdown waits at most 5 s (shutdown_drain_timeout) per stream translator, as SV2 already did. A translator that never drained held the shutdown forever.

Job Declaration Protocol

  • A job-allocation token stays valid through its expiry millisecond, as the token store documents; the mining-job bridge treated that millisecond as expired.
  • Declared transactions are kept as one position-ordered list, and the bridge stores only the fields it reads of a declared job instead of a full copy.

API

  • /api/info reports the front's start time as the pool uptime. The front writes it to Redis (pool:core:started_at) on boot, so restarting the API, payout or notify process no longer resets the uptime. Until the front has been restarted once, the API reports its own start as before.
  • Response-cache entries expire through the cache itself instead of one timer task per insert, so an entry that was invalidated and recomputed is no longer cut short by the old entry's timer.
  • A group mutation also drops the group's cached max-difficulty and window-timeline responses.

Notifications

  • FCM and Web Push (VAPID) tokens are signed with ring directly; jsonwebtoken is removed. Payloads are unchanged.
  • Every push path (fan-out, device status, network-difficulty cron) delivers through one FCM and one UnifiedPush sender, and the three device notices share one routing path and one Telegram sender. The network-difficulty cron now logs a failed prune or stamp instead of dropping the error.

Dependencies and security

  • axum 0.8, tower-http 0.7, tower_governor 0.8, governor 0.10, reqwest 0.13, redis 1.x, thiserror 2, plus the compatible lockfile updates. This clears RUSTSEC-2026-0258 (h2), RUSTSEC-2026-0285 (rustls), the faster-hex and event-listener soundness advisories and a yanked chacha20.
  • Every HTTP client is built through one constructor that installs the ring TLS provider, so the tree carries no second crypto library. Outgoing HTTPS verifies against the system certificate store.
  • The Valkey client is built without TLS, which the pool never used, removing the unmaintained rustls-pemfile (RUSTSEC-2025-0134).
  • CI runs cargo audit on push, on pull requests and weekly; Dependabot proposes updates monthly.

Removed

  • The daily purge of rpc_block_entity: nothing writes that table, so the cron deleted nothing after its first run. The table stays.
  • The Group-Solo per-finder snapshot and round total, which only a fallback no booking reached and tests read.
  • The group and Blockparty routing caches on the payout and notify processes, which never read them; they are built only where the front's routing and the API's group endpoints use them.
  • Code without callers: the leftovers of directed invitations, unused DB queries and row types, unconstructed error variants, the GeoIP configuration nothing set, the hook generics on the API state and services.

Upgrade notes

  • Remove client_diff_scores_secs and group_by_address_secs from [api.cache] before deploying: nothing reads them, and an unknown key fails the config load. Removing them first is safe with v2.3.8.
  • Roll the payout process before the front. The new front no longer sends a Group-Solo snapshot in the block-found event, and an old payout process would leave such a block unbooked. A new payout process with an old front is fine. Blocks already parked in the old format still settle.
  • No new migrations.
  • The Redis keys groupsolo:*:total are no longer read or written and can be deleted.