SuperScalar v0.2.0 Release Notes
v0.2.0-rc1 — release candidate 1, 2026-05-31
v0.2.0 is the first release where SuperScalar is a credible mainnet candidate. It bundles ~265 merged PRs since v0.1.13 — a new canonical leaf shape (Pseudo-Spilman k² sub-factories), a top-to-bottom MuSig2 redesign, PTLC infrastructure, reorg-correctness pre-flight, crash-injection scaffolding, an adversarial cheat-engine campaign, and a trustless standalone watchtower.
This document is the operator-facing summary. See CHANGELOG.md for the full per-PR log.
Headline: Pseudo-Spilman k² sub-factories
The marquee feature of v0.2.0 is the canonical PS leaf shape from zmn t/1242: instead of one client per leaf, each PS leaf now hosts k² clients distributed across k pseudo-Spilman sub-factories, with k clients per sub-factory. The LSP holds "sales stock" inside each sub-factory that can be dynamically chained into new client channels.
For arity k=2 (entry-level production shape):
- 4 clients per leaf vs 1 in pre-PS
- Tree depth drops by ~log₂(4) per leaf compaction
- Lower CSV budget → tighter
final_cltv_deltafor incoming HTLCs - Sales-stock chain extension lets the LSP refill client liquidity without a full leaf re-sign
Implementation landed in 13 staged PRs (Phase 1 foundation → Phase 5 signet campaign), plus the multi-input MuSig ceremony for sub-factory chain advance, force-close persistence, watchtower coverage, on-chain force-close at k=2, per-client channel sweep, and reorg invariants. At k≥3, multi-input keyagg threading is per-input-aware (no more "Invalid Schnorr" at scale).
This is what made the N=64 PS lifecycle on signet + testnet4 not just possible but practical.
Reference docs: docs/ps-subfactories.md, docs/pseudo-spilman.md, docs/factory-arity.md.
Major systems
MuSig2 stateless signer (BIP-327) — default-on
Removed LSP-side secnonce persistence across network waits, per BIP-327 + Bitcoin Core PR #29675 wallet-team guidance. Closes a class of cross-ceremony nonce-reuse attacks that prior pool-based persistence couldn't fully prevent under reorgs and ceremony aborts.
- Phase 0: design audit answering §8 open questions
- Phase 1a:
MSG_CEREMONY_ABORTopcode +--musig-statelessflag (feature-gated, no behavior change) - Phase 1b: wire opcodes for reversed per-leaf advance flow (greenfield)
- Phase 1c: wire reversed per-leaf advance flow behind feature flag
- Phase 1d: poison TX support in stateless per-leaf advance
- Phase 1e: stateless coverage for sub-factory chain advance, Tier B, factory creation
- Phase 2: stateless flipped to default-on (
SS_MUSIG_LEGACY=1opt-out) - Phase 3: legacy
musig_nonce_pool_*API deleted,nonce_poolsSQLite schema dropped permanently - Watchtower registration + poison-TX persist wired into each stateless ceremony
- Unit test asserts the
nonce_poolstable no longer exists (strongest possible invariant — no future refactor can accidentally re-persist secnonces)
Mixed-arity + static-near-root (canonical SuperScalar shape)
The factory builder now implements zmn's full canonical SuperScalar design: TRUE N-way interior branching with optional static-near-root variant for depth reduction.
- Phase 1:
FACTORY_MAX_OUTPUTS8 → 16 - Phase 2: TRUE N-way interior + N-way leaves (arity-N leaf = N+1 outputs)
- Phase 3:
--static-near-root Nmakes N shallowest tree levels kickoff-only (no DW counter) - Phase 4: CLI hardening + BOLT-2016 ceiling check (rejects shapes whose worst-path EWT exceeds 2016 blocks)
- Phase 5: multi-process MuSig coordination at N=8 mixed-arity verified on regtest
- N=128 with
--arity 2,4,8 --static-near-root 2: EWT = 864 blocks (vs binary baseline 3456) FACTORY_MAX_SIGNERS128 → 256 (fixes N=128 LSP stack canary crash)FACTORY_MAX_LEAVES64 → 128
Tier B (multi-leaf state-advance ceremony)
The wire-ceremony equivalent of per-leaf realloc, for when the root DW counter rolls over and every leaf needs re-signing:
- Full implementation with reserved wire IDs
MSG_PATH_NONCE_BUNDLE/ALL_NONCES/PSIG_BUNDLE/SIGN_DONE(0x60–0x63) - Block-driven root rollover semantics (proper, supersedes earlier rc=-1 trigger)
- Client loops
factory_tick_rootuntil rollover - PS leaves re-signed on root rollover + epoch-aware persistence
- Tree-broadcast skips unsigned nodes
- PS sub-factory chain state reset on DW epoch rollover
- Lifted
FACTORY_ARITY_2restriction onlsp_realloc_leaf+buy_liquidity - Rotation log assertion that the poison TX is fully signed (no unsigned-stub fallback)
- Pre-rotation SQLite snapshot hook (
--backup-dir)
PTLC (Point-Time-Locked Contracts) — enabled by default
PTLC is on by default in v0.2.0. Disable with --disable-ptlc if you want HTLC-only channels.
- Watchtower PTLC breach-defense feed (chain-level breach → sweep)
- PTLC turnover ceremony journaled to
signing_rounds - Hard guard against blind-sign seckey extraction in the PTLC pre-sign path
- PTLC commit-tx direction fix
- PTLCs persisted on every channel-add path
- 5 new regtest scripts: basic / breach / restart / chain / breach-chain
- End-to-end PTLC breach test under real chain conditions
Wire-ceremony poison TX — all 4 paths
Multi-process LSPs now produce a fully-signed L-stock / sales-stock poison TX via a second MuSig2 round bundled with every state advance. Prior to this work, the watchtower received an unsigned stub poison TX on multi-process deployments:
- Canonical L-stock SPK + per-client poison TX per zmn t/1242
- Sub-factory advance path
- Leaf advance path (DW + PS leaves)
lsp_realloc_leafTier B per-leaf rotation- Tier B root-rotation poison wire ceremony (LSP + client sides)
- Poison TX persist + rehydrate across LSP restart (schema v22)
- Realloc WT-register fix — registers pre-realloc leaf as stale-watch target (surfaced by the cheat-realloc test)
Trustless watchtower (default + only mode)
The standalone superscalar_watchtower binary now opens only a separate wt.db containing pre-signed response TXs and no secrets. The LSP pre-signs every penalty/sweep/response TX at the moment the relevant secret is in memory and stashes the bytes in wt.db. A compromised WT process cannot construct any new transaction.
Verifiable in one command:
nm -D --defined-only superscalar_watchtower \
| grep -E "persist_load_(basepoints|revocations_flat|channel_for_watchtower|flat_secrets|commitment_sig)"
Expected output: empty.
Four watch kinds covered:
| Watch kind | Trigger | Pre-signed response |
|---|---|---|
WT_KIND_FACTORY_NODE |
Stale factory-node state broadcast | Latest state TX + L-stock poison |
WT_KIND_SUBFACTORY_NODE |
Stale sub-factory chain TX broadcast | Latest chain TX + sales-stock poison |
WT_KIND_CHANNEL_COMMITMENT |
Revoked commitment broadcast | Penalty TX |
WT_KIND_FORCE_CLOSE_HTLC |
Honest force-close confirmed (per HTLC) | HTLC timeout sweep TX |
Link surgery: secret-reader functions moved into superscalar_secrets static library which the LSP/client/tests/bridge link but the WT binary does not.
Reorg correctness — R1–R6 mainnet pre-flight
- R1: detect same-height + forward reorgs (LSP daemon loop + heartbeat)
- R2: wait loops use stable-confirmation helper
- R3: per-network safe confirmation depth
- R4: 3-kind adversarial reorg regression test against standalone WT
- R5:
funding_pending_reorgchannel state (schema v31),MSG_FUNDING_REORGwire, client-sideps_chain_lenreset, proactive mempool-expiry freeze - R6: standalone WT detects forward reorgs
- Schema v29 forensic tables:
reorg_events,breach_detections - Watchtower restart correctness audited end-to-end
- CPFP child-broadcast / anchor mismatch fix (byte-inspection authoritative)
- Sub-factory chain reset on reorg + height-aware reset
- Client-side
ps_chain_lenreset onMSG_FUNDING_REORG
Crash recovery + injection
SUPERSCALAR_CRASH_ATcheckpoint framework- Crash-injection wired at all stateless ceremony phases (PROPOSE / NONCE_BUNDLE / ALL_NONCES / PSIG_BUNDLE / DONE)
MSG_FORCE_OUT+MSG_ROTATEwire ops for crash-drill matrix- Half A: journal SENT-phase participants at every ceremony PROPOSE
- Half C1: crash_checkpoint at all stateless ceremony phases
- Half C2: 16/16 crash-drill matrix tests pass on regtest
- ROTATE ceremony persistence + 4 checkpoints in
lsp_channels_rotate_factory - LSP loadwallet auto-recovery hook
- LSP self-rebroadcasts after mempool eviction
- BIP-68 audit fix for remaining broadcast paths
Cheat-engine adversarial campaign (CL1–CL7)
Seven new cheat drivers exercising worst-case adversary behavior end-to-end:
- CL2:
--cheat-realloc— adversarial pre-realloc-state broadcast - CL3-K:
--cheat-state K+ multistate daemon scaffold - CL4:
--cheat-daemon-rollover— adversarial during Tier B rollover - CL4-multistate: dashboard multistate cheat tests
- CL5:
--cheat-jit— adversarial against JIT channel creation - CL6:
--cheat-lstock-buy— adversarial against buy-liquidity path - CL7:
--cheat-backup-restore— adversarial against SCB restore --cheat-dust-race— adversarial against force-close HTLC-dust-bump race--cheat-clientnet-delta assertion (cheat detection)superscalar_watchtower --inspect-wt-dbfor forensic inspection- Per-cheat regtest script with breach-detection assertions
Schema migrations (v22 → v36)
Each migration is additive (ALTER TABLE ADD COLUMN or CREATE TABLE IF NOT EXISTS), version-gated, idempotent.
- v22: poison TX persist + rehydrate
- v26:
signing_roundsceremony forensics journal - v27: fee-bump escalation persist
- v28: force-close watch persist + subfactory reload
- v29:
reorg_events+breach_detections - v30:
old_commitment_ptlcsschema groundwork - v33:
ps_subfactory_chains.confirmed_height+reorg_stale - v34: ceremony tables for multi-party coordination (
ceremonies,ceremony_participants,revocation_releases) - v35: per-output HTLC sweep TX persistence
- v36: HTLC resolution TX + L-stock burn TX + agg hard guard
- wt.db schema v2:
watch_kinddiscriminant column
Observability + dashboard
- Native Prometheus exporter (LSP-side metrics endpoint)
- Watchtower penalty TX persist + signing_rounds journal
- Per-signer instrumentation in
signing_rounds - 12 dashboard tabs incl. Live Monitor, Defense Status, Payments (HTLC + PTLC), Ceremonies, TX Inventory, Outcomes, Old Commitments, per-POV scoping, multi-client switcher
- Defense Status panel (15-mode failure taxonomy, penalty bytes tile, wallet UTXO + CPFP tiles)
- Outcomes tiles for cheat-* scenarios
- Freshness banner (WAL-aware)
- Production-mode Events derivation
- Tree-node event spam collapsed
- Old Commitments reserve badge
- Factory Config card + PS Leaf Chains panel
BIP-157/158 lite client
- End-to-end + adversarial regtest scripts
- BIP-158 sync headers: seed locator with genesis hash on initial sync
- P2P tip-lag + reconnect storm fix
- Light-client-mode LSP can verify blocks without a full-node RPC backend
Build, packaging, CI
- Multi-platform binaries auto-built on release: Linux x86_64, Linux ARM64, macOS
SHA256SUMSattached to every GitHub releasesuperscalar_secretsCMake static library bundles the secret-bearing TUs (persist_secrets.c,watchtower_autosettle.c,lsp_init_from_db.c,client_reconnect.c) — LSP/client/tests/bridge link it, WT binary does not- Bitcoin Core-style release process documented in
docs/release-process.md - testnet4 fee floor enforcement (0.1 sat/vB minimum across all runner scripts)
setsidwrap for testnet4 long-runners to avoid systemd-logind SIGTERM on SSH session end- Sanitizer regtest job (ASan + TSan) catches leaks in wire-ceremony paths
- 17-script regtest serial sweep on every pre-tag main
Operator tooling
- New
docs/mainnet-runbook.md(full operator runbook) - New
docs/release-process.md(release maintainer checklist) - New
docs/watchtower-trustless-schema.md(trust-model design) - New
docs/deployment-coordination.md(multi-party deployment) - New
docs/poison-tx.md(poison TX semantics) - Setsid-wrapped runner scripts for testnet4 long-runners
- Stderr separation + core dumps + predeath snapshot in testnet4 runners
build-releasedefaults for long-runners (avoid ASan instability)- Sat recovery sweep tooling (
recover_exhibition_funds.py)
Breaking changes
Watchtower CLI: --db removed
Error: --db is no longer a valid flag for the standalone watchtower.
v0.2.0 ships trustless mode as the only mode. Use --wt-db PATH instead.
--inspect-db also removed. Use sqlite3 wt.db directly.
LSP: --wt-db required on mainnet
Error: mainnet requires --wt-db for the trustless watchtower.
v0.2.0 removed the legacy --db-only watchtower mode.
v0.1.x → v0.2.0 migration
- On the LSP: add
--wt-db /path/to/wt.db(any path adjacent tolsp.db). Restart. - On the WT: replace
--db /path/to/lsp.dbwith--wt-db /path/to/wt.db. Restart. lsp.dbstays — the LSP still uses it for channel state, ceremonies, etc. Only the WT process stops touching it.
No schema migration required on lsp.db.
Validation
End-to-end PASS on three independent chains:
- regtest: 19/19 acceptance scripts in the serial sweep
- signet: full N=64 PS lifecycle (21 tree-nodes confirmed at 0.1 sat/vB)
- testnet4: full N=64 PS lifecycle (21 tree-nodes confirmed under live testnet4 attack conditions)
Plus the per-feature regtest suites (PTLC × 5, cheat-engine × 7, crash-drill × 16, sub-factory × 4, watchtower trustless × 3).
Verifying your install
$ nm -D --defined-only $(which superscalar_watchtower) \
| grep -E "persist_load_(basepoints|revocations_flat|channel_for_watchtower|flat_secrets|commitment_sig)"
Expected output: empty. Any line in the output is a regression — file an issue.
Smoke-test on regtest:
$ bash tools/test_regtest_watchtower_trustless.sh