Ship simplepool as a release you can install in one line - #39
Merged
rsantacroce merged 2 commits intoAug 18, 2026
Conversation
Three things, all pointing at the same gap: simplepool was installable only if you already knew how to install it. **A release path.** `scripts/release.sh` builds a tarball, and `.github/workflows/release.yaml` publishes one per architecture on a `v*` tag with a merged SHA256SUMS. The tarball is a git checkout with a prebuilt binary dropped in rather than a trimmed runtime bundle — the systemd units, nginx vhost, schema.sql and dashboard all already expect a checkout at $ROOT, so shipping that shape means the release path and the source path converge after one step instead of forking into two sets of layout assumptions. release.sh refuses a dirty tree: the binary is built from the working tree while the source beside it comes from `git archive`, and on a dirty tree those are two different programs. **An installer that survives being piped.** `install.sh` gains `--from-release [tag]` (now the default when there is no checkout to build) which downloads, verifies against SHA256SUMS, and unpacks — no compiler, no clone. `curl | sudo bash` was already the documented one-liner but could not have worked: BASH_SOURCE[0] is not a readable path when piped, so both the sudo re-exec and `--help` read a file that isn't there. Also fixes the default repo, which pointed at a mirror with no published releases. **`simplepoolctl`.** status / logs / config / doctor / upgrade / uninstall, reading the same /etc/simplepool/install.env the installer writes, so it needs no configuration of its own. `upgrade` re-runs the installer non-interactively rather than reimplementing it, so an upgrade cannot drift from a fresh install. Payouts move to a daily batch, as asked. The subtlety is that PAYOUT_INTERVAL_MS drove both the payout run *and* the settlement re-check of an already-broadcast batch, so setting it to 24h naively would leave a real, already-sent payout uncredited for a day and let a missed BMM request sit unrecovered for the same. Split into three clocks — run (24h), settle (30s), retry (5m) — with nextDelayMs() picking one from what the tick actually did. Long delays are served in hops because setTimeout wraps past ~24.8 days and would turn a monthly cadence into a spin. Adds docs/simplepool.html: one self-contained no-JavaScript page covering both modes end to end, and RELEASING.md for the tag flow. Bumps VERSION to 0.2.0 so tagging v0.2.0 works after this merges — the release job fails a tag that disagrees with the Makefile, since the version is compiled into the binary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`build-test` stalled for 29 minutes and was cancelled by hand. The log
puts it precisely: the Azure mirror `Ign`'d every entry, apt fell back
to archive.ubuntu.com, and the job sat on
Get:5 https://archive.ubuntu.com/ubuntu noble-security InRelease
from 15:51:14 until the cancel at 16:20:01. It never reached package
download — the whole failure was the index refresh.
`apt-get update` on a GitHub runner refreshes six repositories: the
Ubuntu archive plus Microsoft, azure-cli, Google and Chrome. None of
them carry anything simplepool builds against, so the step made every
build depend on all six being reachable in order to fetch 570 kB of
headers. The runner image already ships current lists for the Ubuntu
archive — a plain update reports `Hit:` on the base suite — so the
index on disk is enough to install from.
All four apt steps now call .github/scripts/apt-install.sh, which
installs with no index refresh, bounds every fetch
(Acquire::http::Timeout=20, Retries=3), and falls back to a single
`timeout 180 apt-get update` only if the install actually fails — the
one case the shipped index cannot serve is a package superseded by a
security update whose .deb has left the pool. Every step gets
timeout-minutes: 5, and build-test gets a job-level limit it never had,
which is why nothing capped the 29 minutes.
README: the top described a "solo-mining stratum server" and the body
still said "There is no PPS, no inter-miner reward sharing" — both
written before pps-classic existed and both now false. Those claims are
scoped to `solo`, with the pps-classic inversion stated next to them.
Also drops the stale "sibling project ... in this same monorepo"
framing, fixes a link to ../docs/TESTING.md that pointed outside the
repo, removes include/ from the layout (it doesn't exist) and adds the
modules that do, marks the three shipped roadmap items as shipped, and
states the daily payout cadence where miners will look for it. Points
the source link at LayerTwo-Labs, which is where releases and CI
actually live; the author attribution is untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three things, all pointing at the same gap: simplepool was installable only if you already knew how to install it. Plus the payout cadence change.
1. A release path
scripts/release.shbuilds a tarball;.github/workflows/release.yamlpublishes one per architecture on av*tag, with a mergedSHA256SUMS.schema.sqland the dashboard all already expect a checkout at$ROOT, so shipping that shape means the release path and the source path converge after one step instead of forking into two sets of layout assumptions.release.shrefuses a dirty tree: the binary is built from the working tree while the source beside it comes fromgit archive, and on a dirty tree those are two different programs.--allow-dirtyto override.build/simplepool --versionout of it before publishing — a tarball that doesn't produce a runnable binary never becomes a release.RELEASEfile.2. An installer that survives being piped
--from-release [tag]— downloads the published build for the machine's arch, verifies it againstSHA256SUMS, unpacks. No compiler, no clone. Now the default when there's no checkout to build from;--from-sourcefor the old behaviour.curl | sudo bashcould not have worked.BASH_SOURCE[0]is not a readable path when piped, so both the sudo re-exec and--helpwere reading a file that isn't there. Both now handled.--from-releasefail on a fresh box. NowLayerTwo-Labs/simplepool.build-essential/gitbut still installs the-devpackages, because those are the names that stay put across distro releases (libhiredis-deveverywhere, vslibhiredis0.14on 22.04 andlibhiredis1.1.0on 24.04).3.
simplepoolctlstatus/logs/config/doctor/upgrade/uninstall, reading the same/etc/simplepool/install.envthe installer writes, so it needs no configuration of its own.upgradere-runs the installer non-interactively rather than reimplementing it, so an upgrade cannot drift from a fresh install.doctorchecks the things that actually break: binary runs here, addresses set, schema loaded, data dir writable by the service user, bitcoind answersgetblockchaininfo, something listening on :3334.4. Payouts run daily
As requested — but
PAYOUT_INTERVAL_MSdrove both the payout run and the settlement re-check of an already-broadcast batch. Setting it to 24h naively would have left a real, already-sent payout uncredited for a day, and let a missed BMM request sit unrecovered for the same. Split into three clocks:PAYOUT_INTERVAL_MS— 24hPAYOUT_SETTLE_INTERVAL_MS— 30sPAYOUT_RETRY_INTERVAL_MS— 5mLong delays are served in hops, because
setTimeoutwraps past ~24.8 days and would turn a monthly cadence into a spin that broadcasts every tick.payout/test/cadence.test.jspins every row of that table plus the clamp.5. Docs
docs/simplepool.html— one self-contained, no-JavaScript, theme-aware page covering both modes end to end: shares, the nonce split, difficulty and vardiff, both coinbase shapes, PPS rate derivation, Thunder payouts, the four audit queries, the data model, config, and what the pool can't do.RELEASING.md— the tag flow.Cutting the release after this merges
VERSIONis bumped to 0.2.0, sogit tag v0.2.0 && git push origin v0.2.0publishes immediately. The release job fails a tag that disagrees with the Makefile, because the version is compiled into the binary and a release whose own--versiondiffers from its name makes every later "which version is this box running?" answer untrustworthy.Testing
make test— all 7 C suites passpayout— 56/56 (14 new)dashboard— 76 pass, 2 skipped, 0 failscripts/release.shrun end to end; tarball layout verified against whatinstall.shasserts and what the CI smoke test checksdocs/simplepool.htmlrendered and screenshotted in light and dark; no external assets, no scripts, all 21 anchors resolve, tags balancedTwo bugs found and fixed in my own code while reviewing: the installer's cleanup
trapexpanded alocalthat was out of scope by exit time, makingrm -rf ""fail and take the exit status with it — every successful release install would have ended non-zero; and thesetTimeoutoverflow above.Not tested end to end: the installer itself has not been run on a real Linux box (no Docker daemon available locally, and it guards against non-Linux). The release download path in particular can only be exercised once a release actually exists — which is the next step after this merges.
🤖 Generated with Claude Code