Skip to content

Gravity v1.7.3

Choose a tag to compare

@nekomoto911 nekomoto911 released this 01 Jul 08:18
· 4 commits to branch-v1.7 since this release
fd6c5a3

Gravity v1.7.3

Release: v1.7.3

Full Changelog: v1.7.2...v1.7.3

Related pinned components:

  • gravity-reth: rev 3fd603db — picks up three greth PRs since v1.7.2: #358 (audit-#712 pipe gas_limit + audit-#621 system-tx gas budget), #361 (hardfork stub cleanup), #362 (persist.merge-blocks catch-up)

This release ships Prague activation on mainnet (chain id 127001) plus two consensus-critical audit follow-ups on the pipe-execution gas_limit, and adds a binary-authoritative hardfork schedule so operator misconfig cannot silently disable an activated fork on gravity-owned chains.

Highlights

  • Prague activated on mainnet. #766 sets pragueTime in genesis/mainnet/genesis.json, and #763 introduces GravityChainSpecParser which override-pins pragueTime = 1_782_709_200 for GRAVITY_MAINNET_CHAIN_ID = 127001 at parse time. Any operator-supplied genesis on that chain id is normalised to the governance-pinned value before EL or CL reads it, closing the misconfig path where a mismatched pragueTime (or pragueTime = 0, which silently leaves HISTORY_STORAGE unallocated) would fork the network.
  • CRITICAL: consensus divergence on pipe-block-gas-limit (greth#358, audit-#712). Block gas_limit was sourced from the per-node --gravity.pipe-block-gas-limit CLI flag, so validators with mismatched CLI values produced different block hashes from the same OrderedBlock. Hardcoded to a single workspace const PIPE_BLOCK_GAS_LIMIT = 1_000_000_000; CLI flag, config field, and all init shims removed (mainnet pre-launch, no compat needed).
  • HIGH: gas_used > gas_limit reachable under load (greth#358, audit-#621). System txns (metadata + DKG/JWK) executed before user-tx filtering, then had their gas appended to the block via SystemTxnResult::insert_to_executed_ordered_block_result. Because the filter received the full block.gas_limit as budget, a saturating user block plus non-trivial system overhead could push header.gas_used > header.gas_limit in release builds (validate_execution_output is debug-only). Fix: pass sum_system_gas (exact, computed from already-executed system results) into create_block_for_executor and apply block.gas_limit.saturating_sub(sum_system_gas) to the filter budget. block.header.gas_limit itself stays stable so RPC / indexer semantics are unchanged.
  • Consensus startup hardening (audit follow-ups, #733). Four gravity-audit fixes rolled up: BlockBufferManager::init validation returns errors instead of leaving the manager uninitialised; JWK/DKG validator-tx deserialization replaces unwrap with guarded handling that drops malformed txns; epoch-change readiness synchronises with the BlockStateMachine mutex to close a release-before-consume window on ordered-block reads/writes; GCEI observability (Prometheus counters for filtered txns and coinbase-fallback paths).
  • from-genesis PFN catch-up speedup (greth#362, default off). New gravity.persist.merge-blocks coalesces consecutive blocks into gas/state-bounded groups (MERGE_GROUP_MAX_GAS = 1e9, MERGE_GROUP_MAX_STATE = 1e6 changed accounts) and commits each group with one fsync. Targets from-genesis PFN catch-up which is fsync-bound on the per-block path. Group is atomic (crash rolls back; stage checkpoints re-execute idempotently). Default-off path is byte-for-byte unchanged.
  • Randomness precompile e2e coverage (#751). Single-node coverage of the randomness-by-height precompile plus Solidity wrapper usage; single-node alpha hardfork config switched to alphaTime for the timestamp-gated reth change.
  • PFN transaction-lookup pruning (#752). New PFN prune reth config template selected when prune_transactionlookup_distance is set in node TOML; default PFN template behaviour unchanged when prune is not configured.

Breaking Changes

Chain id 127001 overrides pragueTime from the binary

For GRAVITY_MAINNET_CHAIN_ID = 127001, GravityChainSpecParser (bin/gravity_node/src/chainspec.rs) overrides pragueTime in Genesis to 1_782_709_200 before From<Genesis> for ChainSpec runs in greth. Operator-supplied pragueTime for that chain id is dropped. The override is applied at parse time so the constructed Arc<ChainSpec>genesis_header, fork_id, fork_filter, the inner SealedHeader::hash OnceLock — is correct from t=0 with no post-construction mutation. The CL side (ConsensusHardforks::from_genesis_extra_fields) reads from the same post-override extra_fields, so EL and CL agree on the timestamp with no parallel CL table.

For any chain id not in the table the parser is a no-op and current genesis-driven behaviour is unchanged. alpha_time is currently None on 127001 (forward-defence): no timestamp has been chosen onchain yet, and any operator-supplied alphaTime on mainnet genesis is dropped until governance pins a value.

--gravity.pipe-block-gas-limit CLI flag removed

The per-node --gravity.pipe-block-gas-limit CLI flag / config field / init shims are removed in greth#358. The block gas_limit used by the pipe layer is now a single workspace const PIPE_BLOCK_GAS_LIMIT = 1_000_000_000. Any run scripts / systemd units passing this flag will fail to parse — remove the flag before deploying v1.7.3. block.header.gas_limit semantics on the RPC / indexer side are unchanged.

What's Changed

Genesis / Chainspec

  • chore(genesis): enable Prague on mainnet by @Lchangliang in #766 — sets pragueTime = 1_782_709_200 in genesis/mainnet/genesis.json.
  • feat(chainspec): binary-authoritative hardfork schedule for gravity chains by @nekomoto911 in #763
    • Introduces GravityChainSpecParser in bin/gravity_node/src/chainspec.rs that wraps upstream EthereumChainSpecParser and applies a compile-time override table to the alloy_genesis::Genesis value on the file / inline-JSON fallthrough path, before From<Genesis> for ChainSpec runs in greth.
    • Initial table on 127001: prague_time = Some(1_782_709_200) (governance-pinned to gravity-mainnet-gitops/genesis.json) and alpha_time = None (forward-defence — dropped from operator-supplied genesis until governance picks a value).
    • Named chains (mainnet/sepolia/holesky/hoodi/dev) delegate to upstream unchanged.
    • Maintenance rule: adding or modifying an entry for a shipped chain id is a consensus change; existing entries must never be removed; None → Some(ts) is the only allowed transition.

Bug Fixes — Consensus (audit follow-ups)

  • fix(consensus): harden startup and block buffer handling by @Lchangliang in #733
    • gravity-audit#31: BlockBufferManager::init validation returns errors instead of leaving the manager uninitialised after an early return.
    • gravity-audit#516: JWK/DKG deserialization on validator txns replaces unwrap with guarded handling; malformed validator txns are dropped instead of panicking the node.
    • gravity-audit#522: synchronises epoch-change readiness with the BlockStateMachine mutex, closing a release-before-consume window on ordered-block reads/writes.
    • gravity-audit#598: Prometheus counters for GCEI filtered transactions and coinbase-fallback paths.

Features

  • feat(cluster): support PFN transaction lookup pruning by @Lchangliang in #752
    • New PFN prune reth config template selected when prune_transactionlookup_distance is set in node TOML; default PFN template behaviour unchanged when prune is not configured.
    • Render-checked: PFN deploy with prune_transactionlookup_distance emits --full --prune.transactionlookup.distance=10064; default config keeps --dev and no prune args.
    • Local faucet init works on macOS without GNU timeout; pfn_chain test collects on Python 3.9 (postponed annotations import).

Tests

  • test(e2e): add randomness e2e coverage by @Lchangliang in #751
    • Adds single-node coverage of the randomness-by-height precompile plus Solidity wrapper usage.
    • Switches the single-node alpha hardfork config to alphaTime for the timestamp-gated reth change.
    • Builds the randomness Solidity test contracts inside the Docker e2e runner so new cases have fresh artifacts.

Dependencies (greth)

  • chore(deps): bump gravity-reth to 3fd603db (persist.merge-blocks + pipe gas_limit + hardfork cleanup) by @nekomoto911 in #760
    • Bumps greth 1aec7b75 → 3fd603db, picking up three landed greth PRs — see gravity-reth changes since v1.7.2 below.
    • Note: v1.7.2 was tagged on 2026-06-25 with the old 1aec7b75 pin — greth#358 (merged 2026-06-24) is not in v1.7.2; this bump is the first time it lands in gravity-sdk.

gravity-reth changes since v1.7.2

The greth pin moved from 1aec7b75 to 3fd603db. Three commits:

#358 fix(pipe): close gravity-audit#621 + gravity-audit#712 (3fd603db)

Two consensus-critical fixes to pipe-execution gas_limit plumbing:

  • audit-#712 (HIGH, consensus divergence). Block gas_limit was sourced from the per-node --gravity.pipe-block-gas-limit CLI flag, so validators with mismatched CLI values produced different block hashes from the same OrderedBlock. Hardcoded to a single workspace const PIPE_BLOCK_GAS_LIMIT = 1_000_000_000; the CLI flag, config field, and all init shims are removed (mainnet pre-launch, no compat needed).
  • audit-#621 (HIGH, gas_used > gas_limit). System txns (metadata + DKG/JWK) ran before user-tx filtering, then had their gas appended to the block via SystemTxnResult::insert_to_executed_ordered_block_result. The filter received the full block.gas_limit as budget, so a saturating user block plus non-trivial system overhead could push header.gas_used > header.gas_limit in release builds (validate_execution_output is debug-only). Fix: pass sum_system_gas (exact, computed from already-executed system results) into create_block_for_executor and apply block.gas_limit.saturating_sub(sum_system_gas) to the filter budget; saturating_sub covers the byzantine path. block.header.gas_limit itself is unchanged so RPC / indexer semantics stay stable.

#361 chore: remove gravity hardfork stubs

Drops dead hardfork scaffolding.

#362 feat(persistence): gravity.persist.merge-blocks (default off)

Coalesces consecutive blocks into gas/state-bounded groups (MERGE_GROUP_MAX_GAS = 1e9, MERGE_GROUP_MAX_STATE = 1e6 changed accounts) and commits each group with one fsync. Targets from-genesis PFN catch-up which is fsync-bound on the per-block path. Group is atomic (crash rolls back, recovery re-executes idempotently from stage checkpoints). Default-off path is byte-for-byte unchanged. Also removes the unused --gravity.validator-node-only flag.