feat(v0.2.5): ARM shielded-v2 (bit 2) activation on mainnet + Station PQ send - #26
Merged
Merged
Conversation
…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.
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.
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 offorigin/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.rsmainnet_deployments()Deploymenton bit 2, params matching bits 0/1 exactly:period = 288,threshold = 9/10,lockinontimeout = false.start_height = 14_976— exposed as the single constantMAINNET_SHIELDED_V2_START_HEIGHT. A52·288window 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.0b11→0b111.2.
shielded_v2_activeper-branch resolution (already in-tree; this arms it)Resolves over the block's own parent-branch committed signals via
branch_shielded_v2_active→shielded_v2_active_with→deployment_active_at— the identical shared evaluationfee-auctionuses (fee_auction_active_with→deployment_active_at). Until Active,Action::ShieldedV2is a hard, block-invalidatingFeatureInactivereject;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.rsalready shows/enables shield-v2 / de-shield-v2 / private-v2-send only whenPoolState::classify_v2reports Active, driven bysov_getShieldedV2Info.active=chain.shielded_v2_active(height)— the same consensus resolutionsov_getDeploymentsreports.require_v2_livere-checks before proving;v2_allowsgates every control onpool_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 togetDeployments(equivalent source; a switch would be churn).4. Version + notes
sov-station→ 0.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)
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 isFeatureInactive(producer excludes, smuggled block fails import).daemon.rs), mask0b111,version_bits 0b111.sov-verify::kat_vectors_are_reproduced_byte_for_bytegreen; mainnet replay unaffected (all history < 14,976).cargo fmt --check,cargo clippy --all-targets -D warnings, andcargo testgreen across both workspaces (sov-chain77,sov-governance19,sov-runtime97,sov-shielded-pq71,sov-rpcall,sov-station98).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