Skip to content

feat(evm): restrict parallel precompile state access - #421

Open
AshinGau wants to merge 1 commit into
Galxe:mainfrom
AshinGau:main
Open

feat(evm): restrict parallel precompile state access#421
AshinGau wants to merge 1 commit into
Galxe:mainfrom
AshinGau:main

Conversation

@AshinGau

@AshinGau AshinGau commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Implements the gravity-reth side of Galxe/gravity-audit#1089 and depends on Galxe/grevm#120.

Changes ParallelExecutor::apply_custom_precompiles to accept DynParallelPrecompile, migrates the BLS PoP and randomness user-transaction precompiles to restricted adapters, and keeps system-transaction precompiles explicit and isolated. Shared gas-aware handlers preserve existing output and out-of-gas semantics, while a Clippy disallowed_methods rule prevents direct EvmInternals::db_mut() use; adapter-boundary, gas-boundary, and system-transaction isolation tests cover the migration.

@nekomoto911 nekomoto911 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR correctly lands the gravity-reth side of grevm’s capability-restricted parallel precompile API (DynParallelPrecompile): user-transaction BLS PoP and randomness adapters stop receiving Alloy PrecompileInput / raw EvmInternals, while system-transaction mint (and system BLS) stay on explicit unrestricted DynPrecompile injection. Shared gas-aware handlers preserve existing OOG and output semantics, and the isolation test documents that executor-level custom precompiles already do not leak into transact_system_txn. Dominant residual risk is integration hygiene (unconditional grevm dependency on reth-evm, test-constant drift) rather than parallel-state corruption from these two pure precompiles.

Issue counts by severity

  • bugs: 0
  • suggestions: 2
  • nits: 2

Comment thread crates/evm/evm/Cargo.toml Outdated
reth-storage-api.workspace = true
reth-storage-errors.workspace = true
reth-trie-common.workspace = true
grevm.workspace = true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] grevm is added as an unconditional dependency of reth-evm, which still advertises no_std (#![cfg_attr(not(feature = "std"), no_std)]) and is consumed with default-features = false from the workspace. grevm itself is std-only (rayon, parking_lot, dashmap, etc.), so any reth-evm build without std will pull a non-no_std crate. Parallel execution already leans on std types, but this widens the coupling: every serial/no_std-leaning consumer of the executor traits now depends on grevm solely for the DynParallelPrecompile type on ParallelExecutor.

Suggestion: Gate grevm behind the std feature (or an explicit parallel/grevm feature), and either feature-gate ParallelExecutor::apply_custom_precompiles / the grevm type import, or re-export the type only when that feature is enabled. At minimum, list dep:grevm under std so --no-default-features does not force grevm into the graph.

RandomnessByHeightLookup, RANDOMNESS_BY_HEIGHT_LOOKUP_GAS, RANDOMNESS_BY_HEIGHT_RECENT_GAS,
};
use hex_literal::hex;
use reth_evm::{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Adapter tests hardcode const BLS_POP_VERIFY_GAS: u64 = 110_000 independently of POP_VERIFY_GAS in gravity-precompiles (which remains private). If the production gas constant changes, these tests can keep asserting the stale value and still pass against the adapter only by coincidence (or fail with a confusing mismatch instead of a single shared constant).

Suggestion: Export a public gas constant from gravity-precompiles (e.g. pub const BLS_POP_VERIFY_GAS / re-export POP_VERIFY_GAS) and use it in both the handler and adapter tests.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concrete fix (mirror the randomness gas constants already used in this test module):

  1. In crates/gravity-precompiles/src/bls_pop_verify.rs, export the production constant:
// before
const POP_VERIFY_GAS: u64 = 110_000;

// after
pub const POP_VERIFY_GAS: u64 = 110_000;

No other renames needed in the handler or unit tests inside that crate.

  1. In custom_precompiles.rs #[cfg(test)] module, drop the local copy and import the shared constant:
// remove
const BLS_POP_VERIFY_GAS: u64 = 110_000;

// add (alongside the existing randomness imports)
use gravity_precompiles::bls_pop_verify::POP_VERIFY_GAS;
  1. Replace every BLS_POP_VERIFY_GAS use in the adapter tests with POP_VERIFY_GAS (OOG boundary and success gas_used asserts).

No Cargo.toml change is required — this crate already depends on gravity-precompiles. Optional follow-up: the same local 110_000 / POP_VERIFY_GAS redefinitions in gravity_system_tx_bls_replay_test.rs / gravity_bls_precompile_test.rs can import the public constant the same way.

Comment thread crates/evm/evm/Cargo.toml Outdated
]
metrics = ["std", "dep:metrics", "dep:reth-metrics"]
test-utils = [
"grevm/test-utils",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] test-utils = ["grevm/test-utils", ...] enables grevm’s test fixture stack (metrics-util, serde, etc.) for any crate that enables reth-evm/test-utils. This crate’s PR changes only need the DynParallelPrecompile type in library code; nothing in reth-evm appears to consume grevm’s test_utils module.

Suggestion: Drop "grevm/test-utils" from reth-evm’s test-utils feature unless a concrete reth-evm test needs it. Leave grevm test-utils enablement to crates that actually run grevm e2e fixtures.

Comment thread clippy.toml
"MessagePack",
]
allow-dbg-in-tests = true
disallowed-methods = [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] Workspace clippy now denies only alloy_evm::EvmInternals::db_mut. That matches the audit’s highest-risk escape hatch, but unrestricted Alloy precompiles (still used for system mint) retain other EvmInternals mutators (load_account_mut, sstore, etc.). The reason string frames this as a grevm custom-precompile rule, while the deny is workspace-wide and does not by itself force new user precompiles onto DynParallelPrecompile.

Suggestion: Keep the db_mut deny as defense in depth, but consider also documenting (or linting via a module-level convention) that any precompile registered through apply_custom_precompiles / grevm must be built as DynParallelPrecompile, not ad-hoc DynPrecompile. Optionally expand disallowed methods if future audits identify other journal-bypass entry points still reachable from Alloy PrecompileInput.

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.

2 participants