Skip to content

feat(v0.2.5): ARM shielded-v2 (bit 2) activation on mainnet + Station PQ send - #26

Merged
cloudzombie merged 1 commit into
mainfrom
feat/v0.2.5-shielded-v2-activation
Jul 28, 2026
Merged

feat(v0.2.5): ARM shielded-v2 (bit 2) activation on mainnet + Station PQ send#26
cloudzombie merged 1 commit into
mainfrom
feat/v0.2.5-shielded-v2-activation

Conversation

@cloudzombie

Copy link
Copy Markdown
Owner

Summary

This PR ARMS a consensus feature on live mainnet. It schedules the post-quantum shielded pool (shielded-v2, signal bit 2) for miner-signaled BIP-9 activation and enables SOV Station's PQ send path once activation resolves. Branched off origin/main @ 09ee106 (depth-32 circuit + all six Mediums). PR only — do not merge/tag; the coordinator cuts the release.

Genesis stays frozen. Behavior is byte-identical to 0.2.4 until the activation height — the only immediate change is a mainnet node now stamps version_bits = 0b111 (it signals bit 2).

1. Schedule (consensus) — chain/crates/rpc/src/daemon.rs mainnet_deployments()

  • New Deployment on bit 2, params matching bits 0/1 exactly: period = 288, threshold = 9/10, lockinontimeout = false.
  • start_height = 14_976 — exposed as the single constant MAINNET_SHIELDED_V2_START_HEIGHT. A 52·288 window boundary, ~1,316 blocks (~2.3 days at 2.5 min/block) above the ~13,660 head, so the fleet can be running 0.2.5 and signaling bit 2 before the window opens.
  • min_activation = 15_264 (start+288), timeout = 15_840 (start+3·288) — same offsets bits 0/1 used. Cadence with ≥90% signaling: Started 14,976 → LockedIn 15,264 → Active 15,552.
  • Signal mask 0b110b111.

2. shielded_v2_active per-branch resolution (already in-tree; this arms it)

Resolves over the block's own parent-branch committed signals via branch_shielded_v2_activeshielded_v2_active_withdeployment_active_at — the identical shared evaluation fee-auction uses (fee_auction_active_withdeployment_active_at). Until Active, Action::ShieldedV2 is a hard, block-invalidating FeatureInactive reject; MAX_BLOCK_WEIGHT (PQV2-07) is gated on the same activation.

3. Station PQ send (already dynamically gated; verified, no code change needed)

node/src/gui.rs already shows/enables shield-v2 / de-shield-v2 / private-v2-send only when PoolState::classify_v2 reports Active, driven by sov_getShieldedV2Info.active = chain.shielded_v2_active(height) — the same consensus resolution sov_getDeployments reports. require_v2_live re-checks before proving; v2_allows gates every control on pool_active. It becomes live automatically on activation, stays hidden with an honest "not yet active" state otherwise, and never bypasses the gate. Kept the dedicated-RPC gate rather than switching to getDeployments (equivalent source; a switch would be churn).

4. Version + notes

sov-station0.2.5 (+ Cargo.lock). Release notes: notes/release-v0.2.5.md. Carries the depth-32 tree + all six Mediums. Activation is miner-signaled and requires the fleet on 0.2.5; external circuit audit + QROM remain accepted-pending per the arming bar.

Tests (all green, pasted in the task report)

  • New sov-chain::miner_signaled_shielded_v2_activates_and_a_bundle_executes — mirrors the fee-auction activation test: (a) node signals bit 2; (b) ≥threshold over the window → Active and a real carrier-bound shield executes (value enters pool, supply conserved); (c) before Active it is FeatureInactive (producer excludes, smuggled block fails import).
  • Inverted the mainnet-preset "unarmed" pins to "armed" (daemon.rs), mask 0b111, version_bits 0b111.
  • Consensus KAT sov-verify::kat_vectors_are_reproduced_byte_for_byte green; mainnet replay unaffected (all history < 14,976).

cargo fmt --check, cargo clippy --all-targets -D warnings, and cargo test green across both workspaces (sov-chain 77, sov-governance 19, sov-runtime 97, sov-shielded-pq 71, sov-rpc all, sov-station 98).

Open item for the coordinator

Incidental comments in untouched crates (shielded-pq, state, gas, ledger, types, runtime/execution.rs, sov-wallet.rs) still describe bit 2 as "defined but not armed on any chain." They are not consensus-load-bearing; left untouched for a minimal diff. Worth a follow-up doc sweep.

🤖 Generated with Claude Code

…Station PQ send on activation

Schedules the post-quantum shielded pool for miner-signaled activation on
mainnet and bumps sov-station to 0.2.5. Byte-identical to 0.2.4 until the
activation height; the only immediate change is a mainnet node now signals
bit 2 (version_bits 0b11 -> 0b111).

Consensus (chain/crates/rpc/src/daemon.rs, mainnet_deployments):
- Register the `shielded-v2` deployment on bit 2 with the SAME params bits 0/1
  use: period 288, threshold 9/10, lockinontimeout false. Start height 14_976
  (MAINNET_SHIELDED_V2_START_HEIGHT, a single named constant), a 52*288 window
  boundary ~1,316 blocks (~2.3 days) above the ~13,660 head, so the fleet can be
  on 0.2.5 and signaling before the window opens. min-activation 15_264
  (start+288), timeout 15_840 (start+3*288) -> Active at 15_552.
- Add bit 2 to the mainnet signal mask (0b11 -> 0b111).

Flag wiring (already present in-tree, this arms it): shielded_v2_active resolves
per-branch via branch_shielded_v2_active -> shielded_v2_active_with ->
deployment_active_at, the identical shared evaluation fee-auction uses. Until
Active, Action::ShieldedV2 stays a hard, block-invalidating FeatureInactive
reject; the MAX_BLOCK_WEIGHT bound (PQV2-07) is gated on the same activation.

Station: the PQ send path (shield-v2 / de-shield-v2 / private-v2 send) was
already dynamically gated on sov_getShieldedV2Info.active
(= chain.shielded_v2_active(height), the same consensus resolution
sov_getDeployments reports) via PoolState::classify_v2 + v2_allows(pool_active),
with require_v2_live re-checking before proving. It becomes live automatically on
activation and stays hidden with an honest "not yet active" state otherwise; no
artificial dormant hard-off existed to remove and it never bypasses the gate.

Tests:
- New sov-chain::miner_signaled_shielded_v2_activates_and_a_bundle_executes,
  mirroring the fee-auction activation test: signals bit 2; with >=threshold
  signaling shielded-v2 reaches Active and a real carrier-bound shield EXECUTES
  (value enters the pool, supply conserved); before Active it is FeatureInactive.
- Invert the mainnet-preset unarmed pins to armed (daemon.rs), signal mask 0b111,
  version_bits 0b111.

Carries the depth-32 tree + all six audit Mediums. Activation is miner-signaled
and requires the fleet on 0.2.5; external circuit audit + QROM remain
accepted-pending per the arming bar.
@cloudzombie
cloudzombie merged commit f3b9486 into main Jul 28, 2026
36 checks passed
@cloudzombie
cloudzombie deleted the feat/v0.2.5-shielded-v2-activation branch July 28, 2026 23:54
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.

1 participant