Qbit Mining Bootstrap v3.1.0
Release candidates
Release notes
qbit-mining-bootstrap 3.1.0 Release Notes
Release date: 2026-10-26 (tag v3.1.0, cut from the 3.x.x branch).
3.1.0 is the production release of the 3.x.x line. It is 3.1.0-rc.1 plus
two dependency updates for RustSec advisories, and it changes no runtime code,
setting or migration since rc.1. 3.1.0-rc.1 has run the mainnet pair in
dual-writer mode since 2026-10-20.
Against 3.0.0,
which was cut from the 3.0.x branch, 3.1.0 adds the 3.1 dual
writer and three schema migrations, 027, 028 and 031:
- The dual writer is off by default. With
PRISM_DUAL_WRITERunset, a frontend serves as 3.0's does, once the migrations below are applied. Turned on, it lets two nodes each write their own PostgreSQL and serve miners at once. - Every start requires migrations 027, 028 and 031, whether or not the
dual writer is turned on. 031 builds its index online, so
migratecan run while 3.0.0 or 3.0.0-rc.6 serves (Upgrading).
3.1.0 also contains everything 3.0.0 adds to 3.0.0-rc.6: #770's fix for #765
(import-audits writes each legacy audit before it takes SETTLEMENT_LOCK),
#760's fix for #759 (node RPC clients keep an idle connection for at most
20 s), and the rustls, rustls-webpki and webpki-roots updates.
Everything in the 3.1.0-rc.1 notes applies, with the changes below. They describe the dual writer, its new settings, the migrations, the rollbacks and the dual writer's known limits. The 3.0.0 release candidates' notes, from 3.0.0-rc.1 to 3.0.0-rc.6, apply as the rc.1 notes say.
Changes since 3.1.0-rc.1
- #777: the TLS crates move to their first fixed patch releases, with
cargo update --precise:- rustls-webpki 0.103.15 → 0.103.16 (RUSTSEC-2026-0382), in the root and fuzz lockfiles;
- webpki-roots 1.0.9 → 1.0.10 (RUSTSEC-2026-0381), in the root and fuzz lockfiles;
- rustls 0.23.45 → 0.23.46 (RUSTSEC-2026-0346, RUSTSEC-2026-0347, RUSTSEC-2026-0348 and RUSTSEC-2026-0349), in the fuzz lockfile only; the root lockfile already had 0.23.46 in rc.1.
- tokio 1.53.1 → 1.53.3 (RUSTSEC-2026-0386: tokio's safe
AsyncFdconstructors violate I/O safety), in the root and fuzz lockfiles, asmaintook it in #781. Nothing in the workspace usesAsyncFd. Only tokio's version and checksum change. - The version is 3.1.0.
No other dependency changes.
Upgrading
-
From 3.1.0-rc.1: replace the binary on every frontend and tool, and on the
public-apiservice. 3.1.0 adds no migration and no setting, so there is nothing to migrate or reconfigure: amigratefinds every migration recorded and changes nothing. Nothing refuses a mix of rc.1 and 3.1.0 frontends on one database or across the pair, so they can be replaced one at a time. To roll back, replace the binary with rc.1's. -
From 3.0.0 or 3.0.0-rc.6: first the pre-migrate, then the binary, then, if the pair is to run two writers, the dual-writer cutover.
- Pre-migrate while 3.0 serves. Run 3.1.0's
qbit-prism-server migrateonce, as a one-off command with a frontend's database settings, while the 3.0 frontends keep serving. It applies 027 and 028 in one short transaction, then builds 031's index online, as migration 031 in the migration guide describes. A 3.0 frontend serves, and restarts, at every step: the three migrations declare no capability, so it accepts the database and logs that a later release applied migrations it does not know. #773's tests prove this for 3.0.0-rc.6 frontends under load (R1), and show the build never rewrites the share ledger's data partition (p0); see the rc.1 notes' upgrade from rc.6. 3.0.0 changes neither rc.6's migrations nor its start checks, so the same holds for it. - Then replace the binary on every frontend and tool, and on the
public-apiservice, as in the rc.1 notes' steps 2 and 3. A 3.1.0 frontend or tool refuses the database until 31 is recorded. Pass the new settings only to 3.1.0 binaries: a 3.0runorcheck-configrefuses aPRISM_*name it doesn't know in production mode. From 3.0.0-rc.6, also follow the rc.1 notes' steps 4 and 5: check #760's node rule, and drop #765'simport-auditsguard. From 3.0.0, its own upgrade already covered both. - The dual-writer cutover is optional; with
PRISM_DUAL_WRITERoff, 3.1.0 runs as one writer. Each database is personalised withnode-identity set --index Nbefore its first dual-writer start (dual-writer node identity), and each grants the peer's pulls theprism_peer_syncrole with exactly the grants in the peer sync. The frontends get the dual-writer settings, the carry owner is chosen as in the carry owner and peer settlement, and the balancer routes on/readyz(dual-writer readiness). A node rebuilt from a physical copy of its peer is re-personalised withnode-identity repersonalise --index N(rebuilding a node). The cutover itself is the pair's runbook, as the rc.1 notes' upgrading section says.
Don't overlap the pre-migrate with heavy disk jobs on the database host: fsync starvation can push the serving frontends past their 5 s lock timeouts.
- Pre-migrate while 3.0 serves. Run 3.1.0's
-
From 2.0.x, or from a 3.0.0 candidate before rc.6: as in the 3.0.0-rc.6 notes, with 3.1.0 in rc.6's place: its
migrateapplies 027, 028 and 031 with the rest, and the cutover'smigrate --offline-indexesbuilds 031 offline too. Check #760's node rule (the rc.1 notes' step 4) as well. Animport-auditsbeside serving frontends needs no #765 guard with 3.1.0 (the rc.1 notes' step 5).
Rolling back from 3.1.0 is as the rc.1 notes'
Rolling back describes, with
3.1.0 in rc.1's place. A rollback to 3.0.0 follows its rollback to
3.0.0-rc.6: only from a database that was never personalised, after
removing the dual-writer and readiness settings (3.0.0 knows the two
PRISM_IMPORT_AUDITS_* settings). Unlike a rollback to rc.6, #765 and #759
don't return with 3.0.0. Never start a 3.0.0 or 3.0.0-rc.6 binary on a
personalised database.
Verification
Since rc.1, only the lockfiles, the version and docs have changed, so the rc.1 notes' verification applies. For this release:
cargo deny --locked checkpasses; on 3.1.0-rc.1's tree with #777 it fails on RUSTSEC-2026-0386;- CI runs on the version-bump pull request, including the required
prism-dual-writerlane, and is dispatched on the tag; - the L3 production-window matrix runs on the version-bump pull request, which the tag promotes on a tree match (#608);
- otherwise the evidence set is rc.1's (#557), and the evidence bundle on
the
v3.1.0GitHub release lists every run.
Known issues
As in the 3.1.0-rc.1 notes: no issue listed there has been fixed since. That covers #771, #762, #757 and #758, the dual writer's known limits, and the issues still open from rc.6: #752, #738, #739, #724's other answer, #737's open part, #741, #731, #734, #716's open part, #711 and #712. In addition:
- #716 in the L3 matrix (#779): on 3.0.0's tree, the
throughput-400k-window-2fe-async-3-blockspreset failed its gate in four of six repeats, each with one valid share refused, #716's commit-gate class. 3.1.0 doesn't fix #716, so the preset can fail the same way. #779 also records a steady-state shortfall in one repeat ofthroughput-400k-window-2fe-sync, not yet traced to the code or the runner. - The block-proof acknowledgement bound can drop a pooled connection.
A block-bearing submission's disposition poll runs under that bound. When
the bound expires while the poll is still checking out its connection
(during the pool's ping of an idle connection, or a new connection's
setup), the checkout is cancelled partway and the connection is dropped
with a reply unread. The pool loses that connection, and PostgreSQL logs a
client reset. The submission's answer is unaffected.
mainfixes it in #781 by running each poll in its own task; 3.1.0 doesn't carry that change.