Skip to content

feat(chainspec): hardcode Longevity testnet hardfork timestamps - #843

Open
nekomoto911 wants to merge 4 commits into
mainfrom
feat/testnet-hardcoded-fork-times
Open

nekomoto911 wants to merge 4 commits into
mainfrom
feat/testnet-hardcoded-fork-times

Conversation

@nekomoto911

@nekomoto911 nekomoto911 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Longevity testnet (chain id 7771625) hardfork timestamps become binary-authoritative, like mainnet already is. A testnet node now schedules Prague, Osaka, Alpha, Beta, Gamma, TestnetOwnerFix and TestnetOwnerFixV2 at the on-chain activation timestamps regardless of its genesis file.
  • Why: testnet times were per-node genesis input and the repository copy had already drifted — genesis/testnet/genesis.json lacks testnetOwnerFixV2Time, so a node started from it would never schedule TestnetOwnerFixV2 and would diverge replaying block 32664162. Target release: v1.10.1 (next testnet upgrade).

Architecture and Key Decisions

  • Extends the existing HARDCODED override table in bin/gravity_node/src/chainspec.rs; no new mechanism. The table now covers every Gravity key greth reads from genesis: alphaTime, betaTime, gammaTime, testnetOwnerFixTime, testnetOwnerFixV2Time (plus typed prague_time / osaka_time). The duplicated per-key blocks in apply_overrides are folded into one loop; event format and order are unchanged, new keys report after betaTime.
  • Every hardcoded timestamp (mainnet and testnet, mainnet Prague included) is a named constant in the new bin/gravity_node/src/fork_times.rs, documented with its date, activation block and observed effect; the HARDCODED table only references constants. Pin tests keep literal values as the independent check.
  • Testnet chain id comes from greth's LONGEVITY_TESTNET_CHAIN_ID.
  • Mainnet pins the three new keys to absent. OwnerFix keys are inert on mainnet anyway (greth chain-id gate); Gamma has no chain-id gate, so this prevents a genesis gammaTime from activating Gamma on a single mainnet node before the mainnet time is pinned.
  • Genesis files are not edited: once hardcoded, genesis fork fields no longer drive behavior.
  • TestnetGammaBridge is intentionally not included; it lands with the greth bump that implements it.

Activation evidence (public testnet RPC, 2026-09-30): for each value, the first block with timestamp >= value has its predecessor one second earlier, and the fork's state effect appears in that block.

Fork Timestamp First block Observed effect
Prague 1780909442 1084564 EIP-2935 history contract code appears
Alpha 1783328400 10787823 matches greth #442
Beta / Osaka 1785812400 — no observable state effect; live genesis value
Gamma 1787108400 25666608 NativeOracle runtime swapped (4602 → 3904 bytes)
TestnetOwnerFix 1788490800 30922944 StakePool pendingOwner set
TestnetOwnerFixV2 1788948000 32664162 pendingOwner set to cast-derived address

Risks and Remaining Work

  • Beta/Osaka rest on the live genesis snapshot, not a state observation.
  • Replay of testnet and mainnet state with the v1.10.1 binary remains a release gate.
  • Testnet nodes whose genesis lacks testnetOwnerFixV2Time log one WARN [GravityChainSpecParser] ... binary forces testnetOwnerFixV2Time = 1788948000; genesis says <unset> line at startup and run normally.
  • Pre-existing, not addressed: cargo clippy -p gravity_node with dependencies fails on crates/api FailpointConfResponse dead code under -D warnings.

Breaking Changes

None. Hardcoded values equal on-chain activations; live mainnet genesis (SDK and gravity-mainnet-gitops) has none of the three new keys, so mainnet schedule and startup output are unchanged.

Database Migrations

None.

Verification

  • RUSTFLAGS="--cfg tokio_unstable" cargo test -p gravity_node → 57 passed (38 in chainspec), re-run after the fork_times.rs move. The new testnet tests were observed failing before the testnet entry existed; repository_testnet_genesis_never_contradicts_table failed with TestnetOwnerFixV2: left Never, right Timestamp(1788948000).
  • cargo +nightly-2026-09-05 fmt --all -- --check → clean.
  • RUSTFLAGS="--cfg tokio_unstable" cargo clippy -p gravity_node --no-deps --all-targets --all-features -- -D warnings → clean.
  • E2E not required: pure genesis → ChainSpec transform proven at the parser boundary with the real repository testnet genesis; the startup funnel is unchanged.

Merge Order

None.

Related PRs

None.

The binary becomes the authoritative source of every testnet fork time,
as it already is for mainnet. Values equal the on-chain activations:
Prague, Osaka, Alpha, Beta, Gamma, TestnetOwnerFix, TestnetOwnerFixV2.

The override table now also covers gammaTime, testnetOwnerFixTime and
testnetOwnerFixV2Time; mainnet pins all three to absent, so a genesis
gammaTime cannot activate Gamma on a single mainnet node.
Every timestamp in the HARDCODED table, including mainnet Prague, is now a
named constant in fork_times.rs, documented with its date, activation block
and observed effect. The table only references constants; pin tests keep
literal values as the independent check.
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