Conversation
Adds the consensus state root contract for EIP-4788 as a pre-deploy. This is essentially the same contract as Ethereum's beacon roots contract defined in EIP-4788. The only difference is that the TIMESTAMP (0x42) opcode was replaced with TIMESTAMP_MS (0x4b). The reason for this change is that the contract will store each block's consensus state merkle root using the block's timestamp as the key. Since Seismic has sub-second block times, there will be multiple blocks that return the same value for TIMESTAMP. Those blocks would overwrite each other's consensus state merkle root.
Small refactor to minimize diff with upstream. Think this was changed by mistake. new diff in this PR: ``` ~/devel/seismic-workspace/seismic-reth [refactor--minimize-chain-state-crate-diff-with-upstream] $ git diff main --stat crates/chain-state crates/chain-state/src/in_memory.rs | 6 ++++-- crates/chain-state/src/lib.rs | 2 +- crates/chain-state/src/memory_overlay.rs | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) ``` Current seismic branch diff with main: ``` ~/devel/seismic-workspace/seismic-reth [seismic] $ git diff main --stat crates/chain-state crates/chain-state/Cargo.toml | 5 ++--- crates/chain-state/src/in_memory.rs | 6 ++++-- crates/chain-state/src/lib.rs | 4 +++- crates/chain-state/src/memory_overlay.rs | 6 ++++-- 4 files changed, 13 insertions(+), 8 deletions(-) ``` ## Claude Analysis ``` The diff has 3 related changes: 1. revm-state changed from optional to non-optional (line 30) 2. "revm-state?/serde" commented out in the serde feature (line 71) 3. "revm-state" removed from test-utils feature (line 79) Why it was done: In upstream reth, revm-state is an optional dependency only pulled in by the test-utils feature — it's used solely in test_utils.rs (use revm_state::AccountInfo). The ? syntax in "revm-state?/serde" means "enable serde on revm-state only if it's already enabled." On the seismic branch, someone added use revm_state as _; to lib.rs (not behind #[cfg(feature = "test-utils")]). This is a dummy import that exists only to suppress the unused_crate_dependencies lint (the #![cfg_attr(not(test), warn(unused_crate_dependencies))] at the top). But because this import is unconditional, it requires revm-state to always be present — hence making it non-optional. Once it's non-optional: - The ? conditional syntax in "revm-state?/serde" becomes pointless (it's always present), so it was commented out — though it should have been changed to "revm-state/serde" rather than commented out (this is likely a bug: serde won't propagate to revm-state now). - Listing "revm-state" in test-utils is redundant since it's always included, so it was removed. Was this necessary? No, this change appears unnecessary and introduces a minor bug. The cleaner approach would have been to either: 1. Not add the use revm_state as _; line at all (it's not needed since the crate genuinely uses it in test-utils), or 2. Gate the dummy import behind #[cfg(feature = "test-utils")] And the commented-out "revm-state?/serde" line should be "revm-state/serde" (without ?) to correctly propagate the serde feature. ```
…333) The alloy_compat module (TryFrom<AnyRpcTransaction> for SeismicTransactionSigned) was gated behind an alloy-compat feature that no crate in the workspace ever enabled — making it dead code. Remove the module, the feature flag, and its associated optional dependencies (alloy-rpc-types-eth, alloy-serde, num-traits). Seems like we copied over this code from op when creating our seismic crates. op defines similar feature in op-alloy-consensus, but its only used for reth-bench, and we haven't updated that. Claude also recommends that if we do want this conversion code it should live in seismic-alloy anyways. So feel safe deleting this code from reth. ## Claude analysis ``` The TryFrom<AnyRpcTransaction> conversion is for turning JSON-RPC transaction responses into reth-native types. The concrete use case would be something like: // Fetch a tx from a Seismic RPC node let rpc_tx: AnyRpcTransaction = provider.get_transaction_by_hash(hash).await?; // Convert to reth's internal type let signed_tx: SeismicTransactionSigned = rpc_tx.try_into()?; But nobody does this. In practice: - reth receives transactions either via p2p (already native types) or via eth_sendRawTransaction (raw RLP bytes decoded directly, not JSON-RPC format). The RPC→native conversion is never needed. - Foundry doesn't use reth-seismic-primitives at all — it has its own transaction types. - Upstream reth-primitives has alloy-compat = [] (empty!) — it's just a marker feature. The actual conversions live in op-alloy-consensus, not in reth itself. So to answer your question: no, you don't need this code right now. It's a speculative compatibility shim that nothing calls. The only scenario where it would matter is if some future tool needs to fetch Seismic transactions from an RPC endpoint and convert them to reth-internal types — but that tool doesn't exist yet, and if it did, the conversions would arguably belong in seismic-alloy-consensus (like upstream puts them in op-alloy-consensus), not in reth-seismic-primitives. ```
There were a few issues when test fails:
1. started reth binary not killed
2. nextest restarts the test 4 times, but all 3 extra times just fail
due to port conflict with non-cleaned leftover binary
3. also test would panic reporting failure
Changed nextest.toml config to only run this test once.
## More involved future improvements
I feel like the test harness with compiling at beginning of test (!) +
running a reth binary is overkill. Claude seems to agree with me:
```
What SeismicRethTestCommand does
It shells out to cargo run --bin seismic-reth at runtime (utils.rs:47), which means:
1. Recompiles reth from scratch inside the test — a full cargo run that re-invokes the compiler
2. Parses stdout waiting for "Starting consensus engine" to know it's ready
3. Communicates over HTTP RPC on a hardcoded port (127.0.0.1:8545) — no isolation, port conflicts possible
4. Uses mpsc channels + kill_on_drop for lifecycle management — brittle compared to in-process
What upstream reth does instead
Reth already has reth_e2e_test_utils which starts a full node in-process — no subprocess, no recompilation. The pattern from
crates/ethereum/node/tests/e2e/eth.rs:
let (mut nodes, _tasks, wallet) = setup::<EthereumNode>(
1, Arc::new(chain_spec), false, eth_payload_attributes,
).await?;
let mut node = nodes.pop().unwrap();
// inject tx, advance block, assert — all in-process
let raw_tx = TransactionTestContext::transfer_tx_bytes(1, wallet.inner).await;
let tx_hash = node.rpc.inject_tx(raw_tx).await?;
let payload = node.advance_block().await?;
This uses NodeBuilder::new(config).testing_node(executor) which creates an ephemeral TempDatabase, starts the node in the same process/tokio runtime,
and gives you direct programmatic access to all internals (pool, provider, network, RPC, payload builder).
Benefits of switching to in-process
- No double compilation — reth is compiled once as part of the test binary, not again at runtime via cargo run
- No port conflicts — RPC is in-process, no hardcoded 8545
- Better isolation — each test gets its own TempDatabase
- Direct access — you can call into node internals, not just HTTP RPC
- Proper lifecycle — no process management, stdout parsing, or kill_on_drop
So yes — the test should use setup::<SeismicNode>(...) (or equivalent) instead of SeismicRethTestCommand. The only reason this approach might have been
used is if SeismicNode didn't yet implement the traits needed by the NodeBuilder test infrastructure, but that would be the right thing to fix.
```
## Summary - Replaces the inline-prompt claude review workflow with a sticky-comment architecture that edits a single comment in-place on each push (no duplicate comments) - Moves the review prompt to `.claude/prompts/claude-pr-review.md`, tailored to seismic-reth (confidential txs, enclave/TEE, flagged storage, precompiles, hardforks, clippy strictness) - Adds `reopened`/`synchronize` triggers, dependabot + merge queue exclusions, 20min timeout ## Test plan - [ ] Open a test PR and verify the workflow triggers on `opened` - [ ] Push a follow-up commit and verify the sticky comment is updated in-place (not duplicated) - [ ] Comment `@claude` on a PR and verify the `issue_comment` trigger works - [ ] Verify dependabot PRs and draft PRs do not trigger the workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
|
Comparison PR showing the complete delta between Seismic fork and upstream reth (300+ files). Assessment This is a meta-PR for tracking fork divergence, not a code change for review. The "[DONT MERGE]" prefix and empty body confirm it's documentation-only. Purpose served:
No actionable review needed - this is working as intended for a comparison PR. The large file count (300+) is expected when showing an entire fork's delta. LGTM for its intended purpose as a comparison tool. |
## Summary - Removes stale `default-filter` from `.config/nextest.toml` that was excluding 8 tests from CI - All 8 tests pass locally — the filters were likely added during early development and never revisited ## Tests re-enabled **Static file truncation tests** (`reth-provider`): - `providers::static_file::tests::test_header_truncation` - `providers::static_file::tests::test_tx_based_truncation` **Fee history RPC tests** (`reth-rpc`): - `eth::core::tests::test_fee_history_empty` - `eth::core::tests::test_fee_history_all_blocks` - `eth::core::tests::test_fee_history_no_block_requested` - `eth::core::tests::test_fee_history_invalid_block_range_in_future` - `eth::core::tests::test_fee_history_invalid_block_range_before_genesis` - `eth::core::tests::test_fee_history_single_block` ## Test plan - [x] Ran `test_header_truncation` and `test_tx_based_truncation` locally — both pass - [x] Ran all 6 `eth::core::tests` locally — all pass - [x] CI passes with the filter removed
2 main changes from revm: 1. CLOAD is now allowed to read public storage (had to fix a test). See SeismicSystems/seismic-revm#180 - this is a pretty old PR now, its even on the seismic branch and not the audit branch. We were just pointing to a very old commit. 2. SeismicHaltReason no longer exists. Changed invalid public/private access to reverts instead of halts. See SeismicSystems/seismic-revm#210 for more details
… test (#335) ## Summary - Registers `EthConfigHandler` in the Seismic node's RPC add-ons, enabling the `eth_config` RPC method ([EIP-7910](https://eips.ethereum.org/EIPS/eip-7910)). This was already wired in the Ethereum node but missing from the Seismic node. - Adds `test_mercury_hardfork_config` E2E test that validates Mercury hardfork configuration is correctly reported via `eth_config`. ## Changes ### `crates/seismic/node/src/node.rs` - Register `EthConfigHandler` in `SeismicAddOns::launch_add_ons`, merged into the `Eth` RPC namespace — matches upstream `EthereumNode` pattern at `crates/ethereum/node/src/node.rs:304-316` - This is a non-breaking, additive change: adds `eth_config` alongside existing `eth_*` methods ### `crates/seismic/node/tests/e2e/hardfork_config.rs` (new) - Starts a `SeismicNode` (not `EthereumNode`) with `SEISMIC_DEV` chain spec - Initializes mock purpose keys via `std::sync::Once` (required for in-process Seismic node startup) - Calls `eth_config` RPC and asserts: - `activation_time == 0` — Mercury active at genesis - `chain_id` matches Seismic dev chain (5124) - `fork_id` matches locally computed fork hash from `chain_spec.fork_id()` — this is a CRC32 of the genesis hash XOR'd with all active fork timestamps, proving the full Seismic fork schedule and genesis state (including system contracts) is correct - No next fork scheduled - Note: `precompiles` field is not asserted because `EthConfigHandler` currently returns an empty map (upstream TODO at `crates/rpc/rpc-eth-api/src/helpers/config.rs:103`) ### `crates/seismic/node/tests/e2e/main.rs` - Adds `mod hardfork_config` and clippy allows for test code ### `crates/ethereum/primitives/src/receipt.rs` - Import reorder to match CI nightly rustfmt ## Test plan - [x] `cargo nextest run -p reth-seismic-node -E 'test(mercury_hardfork_config)'` passes locally - [x] `cargo clippy -p reth-seismic-node --tests --no-deps` clean - [x] `cargo +nightly fmt --all` clean - [ ] CI passes
## Summary Re-enables the commented-out `mod testsuite` in seismic E2E tests and fixes compilation errors that accumulated since it was disabled. ## Changes **`crates/seismic/node/tests/e2e/main.rs`**: - Uncomments `mod testsuite;` - Adds `clippy::unwrap_used`, `clippy::expect_used` allows (standard for test files) **`crates/seismic/node/tests/e2e/testsuite.rs`**: - Fix import paths: `SeismicEngineTypes`/`SeismicNode` moved to `engine`/`node` submodules - Use `SEISMIC_MAINNET.clone()` directly instead of `ChainSpecBuilder` + missing genesis.json asset - Flatten `PayloadAttributes` to match current `SeismicEngineTypes` (was using old nested Optimism-style wrapper) - Set post-Cancun required fields: `withdrawals: Some(vec![])`, `parent_beacon_block_root: Some(B256::ZERO)` - Rename `test_testsuite_op_assert_mine_block` → `test_testsuite_seismic_assert_mine_block` - Change expected hash from `Some(B256::ZERO)` → `None` (block hash can't be predicted) - Extract `SEISMIC_TIMESTAMP_MULTIPLIER` constant to replace magic number 1000 ## Test plan - [x] `cargo clippy -p reth-seismic-node --tests --no-deps` passes - [x] `cargo +nightly fmt --all` clean - [x] CI passes 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary - Re-enable the `mod p2p` E2E test module that was previously commented out - Fix `utils::setup()` to use `SEISMIC_DEV` chain spec instead of a vanilla Ethereum Cancun spec, so p2p tests actually run with Seismic fork rules - Deduplicate test helpers: move `ensure_mock_purpose_keys()`, `SEISMIC_TIMESTAMP_MULTIPLIER`, and `seismic_payload_attributes()` into shared `utils.rs` - Fix `seismic_payload_attributes()` to apply the millisecond timestamp multiplier - Remove unused `seismic-alloy-genesis` dependency from test-utils feature ## Test plan - [x] `cargo +nightly fmt --all` clean - [x] `cargo clippy -p reth-seismic-node --tests --no-deps` passes (seismic-strict) - [ ] CI passes 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…346) ## Summary - Add known Seismic antipatterns (wrong chain spec, missing timestamp multiplier, wrong node type) to the Claude PR review prompt as Phase 1 critical issues - Add a dedicated "Known Antipatterns" section to the review guidelines for patterns that are always bugs in Seismic code - Grant the Claude review bot `Read` and `Grep` tools so it can follow imports and verify semantic correctness when reviewing changes to `crates/seismic/` ## Test plan - [ ] Verify the Claude PR review workflow triggers correctly on a test PR - [ ] Confirm the bot can use Read/Grep to inspect files beyond the diff 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Replace the commented-out `cargo build` step with `cargo check --workspace` for fast (~30s) workspace-wide compilation validation - Provides early feedback before slower test jobs finish - Future improvement: upgrade to `cargo hack check --workspace` (like upstream reth) once the pre-existing `SerdeBincodeCompat` trait bound issue in `reth-ethereum-primitives` is fixed ## Test plan - [ ] Verify the new `cargo check --workspace` step passes in CI 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…recovered_tx (#349) Same fix as that from SeismicSystems/seismic-evm#42 Not sure if there was an issue here, but its just unnecessary duplicate code that is likely to contain a bug like it did in evm.
…ta (#350) ## Summary Fixes #348 ### Problem `setup_engine_with_chain_import` hardcoded `EthereumNode`, so any chain import test that used a non-Ethereum node type (like `SeismicNode`) would re-execute blocks with the wrong EVM, producing state root mismatches. ### Changes **Generic chain import framework** (`crates/e2e-test-utils/`): - Make `ChainImportResult<N>` and `setup_engine_with_chain_import<N>` generic over the node type - Accept `evm_config` parameter instead of hardcoding `EthEvmConfig` - Type-erase `import_result_holder` in `Setup` via `Box<dyn Any + Send + Sync>` - Add `run_with_evm<N>()` on `TestBuilder` for non-Ethereum node types - Add `apply_with_import_and_evm<N>()` on `Setup` for custom EVM configs - Existing `EthereumNode` callers unchanged (backward compatible) **Seismic RPC compat test** (`crates/seismic/node/tests/e2e/`): - Add `rpc_compat.rs` with `test_seismic_rpc_compat` using `SeismicNode` + `SeismicEvmConfig` - Add test data in `testdata/rpc-compat/`: 665 blocks from a live Summit testnet (chain ID 5124, real consensus), with an ssolc-compiled EventEmitter contract using `suint256` private storage - Upstream `rpc-e2e-tests` left untouched (`EthereumNode`, `#[ignore]`) ## Test plan - [x] `cargo check -p reth-e2e-test-utils --tests` compiles - [x] `cargo check -p reth-seismic-node --tests` compiles - [x] `cargo nextest run -p reth-seismic-node --test e2e -E 'test(rpc_compat)'` passes (1.3s) - [x] Upstream `rpc-e2e-tests` unchanged - [ ] CI passes --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix StorageProof::verify to encode values as FlaggedStorage (value + privacy flag byte) instead of raw U256, matching what the trie stores. Add test_flagged_storage_proof covering mixed public/private storage slots.
…352) ## Summary Replaces the subprocess-based integration test architecture (`cargo run --bin seismic-reth`) with in-process node testing via `setup(1)` + `advance_block()`, matching the pattern used by upstream reth and already adopted by our `p2p.rs`, `testsuite.rs`, and `hardfork_config.rs` tests. - **Split monolithic `integration_test` into 9 independent `#[tokio::test]` functions** — each spawns its own in-process node on random ports, enabling parallel execution and individual failure reporting - **Move Seismic RPC registration into `SeismicAddOns::launch_add_ons`** — `EthApiExt` (eth_ overrides) and `SeismicApi` (seismic_ namespace) are now registered as part of the node's add-ons lifecycle instead of via `extend_rpc_modules` in `main.rs`. This ensures both the binary and in-process test nodes get the full Seismic RPC surface. - **Remove `SeismicRethTestCommand`** — the subprocess launcher (`cargo run --bin seismic-reth`) and its stdout-parsing readiness detection are no longer needed - **Extract shared async helpers** to keep async state machines small (`rpc_test_deploy_contract`, `flagged_storage_deploy_and_write`, etc.) - **Heap-allocate node setup via `tokio::spawn`** to avoid stack overflow on x86_64 CI (see below) - **Re-export `FullSeismicApi`** from `reth_seismic_rpc::eth` module so `pub use eth::*` pulls it in cleanly ## Stack overflow on x86_64 CI The in-process tests overflow the default 2MB thread stack on x86_64 Linux CI, but not on ARM64 macOS locally. **Root cause**: Rust compiles each `async fn` into a state machine enum where every `.await` point becomes a variant holding all locals live across that point. The test futures are large because they hold `SeismicTestNode` (contains the entire running node's state — provider, pool, network, RPC registry) plus sub-futures for RPC calls, all composed into a single enum. The total future size + the call chain depth (tokio runtime → test state machine → jsonrpsee client → jsonrpsee server → Seismic RPC handler → EVM execution) exceeds 2MB on x86_64. **Why x86_64 but not ARM64**: x86_64 has 16 general-purpose registers vs ARM64's 31. Fewer registers means more local variables spill to the stack, making each function's stack frame ~30-50% larger. The same Rust code that fits in 2MB on ARM64 overflows on x86_64 in debug builds. **Fix**: `tokio::spawn(setup(1))` in `setup_test_node()` moves the large `setup` future from the caller's stack onto the heap. `tokio::spawn` boxes the future internally (`Box::pin`) and runs it on a worker thread as a standalone task — the caller only holds a lightweight `JoinHandle` on their stack. This eliminates the need for `RUST_MIN_STACK` entirely and is robust against future growth in test logic. ## What changed | File | Change | |------|--------| | `crates/seismic/node/tests/e2e/integration.rs` | 9 independent in-process tests with extracted helpers; `tokio::spawn` for node setup | | `crates/seismic/node/src/node.rs` | Register `EthApiExt` + `SeismicApi` in `launch_add_ons` | | `crates/seismic/node/src/utils.rs` | Remove `SeismicRethTestCommand` | | `crates/seismic/rpc/src/lib.rs` | Simplified to `pub use eth::*` (FullSeismicApi re-exported from eth/mod.rs) | | `crates/seismic/rpc/src/eth/mod.rs` | Added `pub use api::FullSeismicApi` | | `bin/seismic-reth/src/main.rs` | Remove redundant `extend_rpc_modules` (now in `launch_add_ons`) | | `crates/seismic/node/Cargo.toml` | Remove unused deps (`once_cell`, `tempfile`), make `serde_json` dev-only | | `.github/workflows/seismic.yml` | Removed `RUST_MIN_STACK` (no longer needed) | | `.config/nextest.toml` | Remove stale port-conflict override | ## Why Issue #338 identified that the subprocess test architecture was: 1. **Slow** — `cargo run` reinvokes the compiler at test time 2. **Brittle** — hardcoded port 8545, stdout parsing for readiness 3. **Non-isolated** — all tests shared one node, no parallel execution The in-process approach eliminates all three: the node compiles once as part of the test binary, each test gets its own ephemeral database and random ports, and blocks are produced deterministically via `advance_block()` instead of `thread::sleep`. ## Test plan - [x] `cargo nextest run -p reth-seismic-node -E 'kind(test)' --no-fail-fast` — all 15 tests pass locally (no `RUST_MIN_STACK` needed) - [x] `cargo check -p reth-seismic-rpc -p reth-seismic-node` — compiles clean - [x] `cargo clippy` with CI flags — no errors - [x] `cargo check -p seismic-reth` — binary still compiles - [x] `cargo +nightly fmt --all --check` — formatted Closes #338 --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
) ## Summary - Added `SeismicFullNode` supertrait alias in `node.rs` that bundles the verbose `FullNodeComponents<Types: NodeTypes<ChainSpec=ChainSpec, Primitives=SeismicPrimitives, ...>>` bound - Replaced the repeated 8-line bound block across 6 `impl` blocks with the single alias - Net: 35 insertions, 47 deletions — the trait definition is ~28 lines but eliminates 6 repetitions Addresses #352 (comment) ## Test plan - [x] `cargo check -p reth-seismic-node -p reth-seismic-rpc -p seismic-reth` — compiles clean - [x] `cargo nextest run -p reth-seismic-node -E 'kind(test)' --no-fail-fast` — all integration tests pass - [x] `cargo +nightly fmt --all` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Revert crates/optimism/ to match upstream (zero diff) and remove optimism workspace dependency entries from root Cargo.toml. Comment out the three optional reth-optimism-* deps in db-api, rpc-convert, and engine/local that were causing cargo to resolve and compile the optimism crates (which fail due to our FlaggedStorage/Genesis changes). cargo clippy --workspace now passes cleanly. This will be easier to maintain going forward. Instead of having to fix stuff that we implicitly break in op code, we just disable op code entirely from being compiled/linted. ## Timestamp-ms note The`test_discv5_fork_id_default` test was passing in CI before because reth-optimism-chainspec's dev-dependency [enabled](https://github.com/SeismicSystems/seismic-reth/blob/9382370ab423b142fb5572155258049e98919e04/crates/optimism/chainspec/Cargo.toml#L54) timestamp-in-seconds on reth-chainspec. This PR removed that though. Cargo feature unification meant this flag leaked to the entire workspace during cargo test --workspace which we were using in CI, so the network test silently ran in seconds mode. However note that the test failed when ran directly via cargo nextest run -p reth-network test_discv5_fork_id_default. So this fix is more principled. Also the timestamp-in-seconds flag was not even a feature of the network crate. Fix: use separate constants — GENESIS_TIME (ms) for genesis/head timestamps, GENESIS_TIME_SECONDS (s) for ForkCondition and ForkId. ### Future improvements Longer term, we should unify to ms everywhere — including ForkCondition::Timestamp — and only keep the timestamp-in-seconds feature flag for ef-tests (whose fixtures have seconds baked into RLP-encoded blocks). This would eliminate the unit mismatch and the ~26 scattered cfg!/conversion sites across 4 repos. Here is Claude's plan: ``` Combine A's "ms everywhere" approach with a retained feature flag scoped to ef-tests only. Production code uses ms for everything — `header.timestamp`, `Head.timestamp`, and `ForkCondition::Timestamp` are all ms. This means the conversion code in `spec.rs` (`* 1000`, `/ 1000`, `genesis_timestamp_seconds()`) is deleted, not made unconditional. The `cfg!` checks only survive in the few code paths ef-tests exercise (TIMESTAMP/TIMESTAMPMS opcodes in seismic-revm, fork activation in seismic-reth chainspec). **Pros:** - Production code has one unit everywhere: ms. No conversions in fork activation, fork ID, or fork filter - Eliminates ~20 Cargo.toml propagation entries from production - ef-tests continue to pass using the seconds path (flag ON: fork conditions in seconds, header timestamps in seconds, no conversions) - Unit tests throughout the codebase use ms consistently - The `cfg!` checks that remain are only exercised by ef-tests **Cons:** - Feature flag still exists (in seismic-revm's block_info.rs and seismic-reth's chainspec) - Two code paths still compiled, just one is only used by ef-tests - RPCs still return ms (breaks standard tooling without the proxy) - `ForkId.next` contains ms in production, diverging from Ethereum p2p convention (acceptable — Seismic has its own network) **Scope:** | Repo | Work | |------|------| | seismic-reth | Remove flag from `bin/seismic-reth/Cargo.toml` and ~18 production crate Cargo.toml entries. Delete conversion code in production paths (`* 1000`, `/ 1000`, `genesis_timestamp_seconds()`). Update Seismic chainspecs to store ms in `ForkCondition::Timestamp`. Keep `cfg!` in `chainspec/src/spec.rs` for ef-tests. Update ~10 unit tests. Keep flag in `testing/ef-tests/Cargo.toml`. | | seismic-revm | Keep `cfg!` in `block_info.rs` (TIMESTAMP/TIMESTAMPMS opcodes, needed for ef-tests). Remove flag from production Cargo.toml propagation. | | seismic-evm | Remove `cfg!` checks entirely (ef-tests use `EthEvmConfig`, not `SeismicEvmConfig`). Remove from Cargo.toml. | | seismic-foundry | ~1 test update, Cargo.toml cleanup. | **Verdict:** Best balance. Cleanest production code (no conversions), ef-tests still work. ```
) Replace seismic_alloy_genesis::Genesis with upstream alloy_genesis::Genesis in ChainSpec.genesis. This reduces our fork diff in core upstream crates (chainspec, optimism, cli) by keeping the genesis type stock. Why: seismic_alloy_genesis::Genesis uses FlaggedStorage for storage values (carrying an is_private flag), but our genesis JSON files don't use private storage — all storage values are plain hex strings, which alloy_genesis handles identically. Using the stock type removes seismic-specific imports from upstream crates that don't need them. What changed: - ChainSpec.genesis and EthChainSpec::genesis() now return &alloy_genesis::Genesis - parse_genesis() in CLI now returns alloy_genesis::Genesis (zero diff from upstream) - DB layer still uses seismic_alloy_genesis::GenesisAccount for its codec (FlaggedStorage encoding). The conversion boundary is in init_genesis() where alloy_genesis::GenesisAccount is converted to seismic_alloy_genesis::GenesisAccount via the existing lossless From impl (marks all storage as public). - Same conversion added in stage/drop.rs for the stage reset path. - Account::from now has impls for both genesis account types. - Optimism chainspec updated to use alloy_genesis types directly. Future compatibility: If private genesis storage is ever needed, only the DB boundary code (init.rs) and seismic chainspec construction would need to change. ChainSpec stays stock. ## Diff Explained Our diff wrt upstream (main branch) has increased overall, but the conceptual diff has been reduced and is better organized. Conceptual wins: - ChainSpec.genesis is now stock — this is the most important one. It's the type that flows through the entire codebase. Every upstream crate that touches chain.genesis() now sees a stock type. - cli/cli/src/chainspec.rs — zero diff, fully stock - optimism/chainspec/ — closer to stock, fewer seismic concepts bleeding in Conceptual losses: - init.rs now has an explicit conversion boundary (alloy_genesis → seismic_alloy_genesis) that didn't exist before. But this is the right place for it — it's the DB boundary where B256 becomes FlaggedStorage. Previously the conversion was hidden in the genesis deserialization (JSON → seismic type), scattered across every callsite that parsed a genesis file. - drop.rs has the same conversion — annoying but same pattern, same boundary - account.rs has two From impls — duplication, but both are trivial 3-liners The concentrated boundary: All the seismic-specific complexity now lives in two spots: 1. The DB boundary (init.rs, drop.rs) — "stock genesis goes in, FlaggedStorage comes out for DB" 2. SeismicHardforks impl in chainspec/spec.rs — forced by orphan rule
Wire trace sanitization into all debug/trace RPC handlers. Depends on SeismicSystems/seismic-revm-inspectors#40 Call sanitize_geth_trace, sanitize_trace_results, and sanitize_localized_transaction_trace from every debug/trace RPC handler before returning results to callers. The sanitizer functions live in seismic-revm-inspectors (trace_sanitizer module) so all trace privacy logic is auditable in one crate. Handlers sanitized: - debug_traceTransaction, debug_traceBlock, debug_traceBlockByHash, debug_traceBlockByNumber, debug_traceCall, debug_traceCallMany - trace_call, trace_callMany, trace_rawTransaction, trace_replayTransaction, trace_replayBlockTransactions, trace_block, trace_filter, trace_get, trace_transaction Also: - Remove unused `reth` dependency from bin/seismic-reth (it was pulling in reth-node-ethereum which enabled js-tracer, causing compile errors since the js-tracer feature is now a no-op in seismic-revm-inspectors) - Pass filter_private_storage=true to populate_state_diff in trace.rs - Remove EofCreate match arm in otterscan (compat with pinned alloy)
Update seismic dependencies (alloy, revm, evm) and fix anything that needs updates in reth: - Add `authorization_list: Vec<SignedAuthorization>` (EIP-7702) to TxSeismic, including Compact codec encoding/decoding and tests - Add `CodeOverrideNotPermitted` variant to `EthApiError` to handle the new `StateOverrideError` variant from seismic-evm (Seismic disallows code overrides for privacy) - Remove `RngMode` from all call sites — seismic-revm no longer exposes it on `SeismicTransaction` (rng mode is now determined internally) - Delegate `SeismicTypedTransaction::Seismic` to `TxEnv::from_recovered_tx` now that seismic-evm provides the impl - Collapse two raw-tx tests into one self-contained roundtrip test (hash was invalidated by the authorization_list field change) Related PRs: - SeismicSystems/seismic-alloy#82 - SeismicSystems/seismic-evm#45 - SeismicSystems/seismic-revm#189 Note that this is a breaking change, since the tx's rlp encoding is changed, which breaks all of: wire format, db format (whats stored in tx trie), and signatures (signing over different rlp encoding). --------- Co-authored-by: Henry Baldwin <henrymbaldwin@proton.me>
## Summary The rpc_compat test previously used the hardcoded `SEISMIC_DEV` chainspec to initialize the node, but the test chain data (`chain.rlp`) was generated from a specific genesis at a specific point in time. If `SEISMIC_DEV` diverges from that genesis, the test breaks — not from a regression, but from a genesis mismatch. This PR loads `genesis.json` from the testdata directory instead, so the node is always initialized with the same genesis that produced the chain data. ## Changes - **`rpc_compat.rs`**: Load and parse `genesis.json` from testdata, build a `ChainSpec` from it using `SEISMIC_DEV_HARDFORKS`, use that for both `Setup` and `SeismicEvmConfig` - **`genesis.json`**: Remove 19 extra Hardhat-default accounts that weren't present in the genesis used to generate `chain.rlp` (caused state root mismatch) - **`Cargo.toml`**: Add `alloy-chains` and `reth-seismic-forks` as dev-dependencies ## Test plan - [x] `cargo test -p reth-seismic-node --test e2e -- test_seismic_rpc_compat` passes
…ller spoofing (#366) Response to this audit issue: <SeismicSystems/mirror--seismic-reth#4> Reliant on [this seismic-alloy pr](SeismicSystems/seismic-alloy#98). **DO NOT MERGE** before updating the seismic-alloy deps in `Cargo.toml` upon merging that pr. --------- Co-authored-by: daltoncoder <daltoncoder2@gmail.com>
(Continued from #356) This adds an authorized endpoint that behaves like eth_getStorageAt. The governance key (security council multisig) can temporarily whitelist a key (Ethereum address) that can access this endpoint. Whitelisted keys can be revoked by the governance key. The governance key is read from the first slot of the protocol params contract: ``` "0x0000000000000000000000000000506172616d73": { "balance": "0x0", "code": "0x60806...", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xd412c5ecd343e264381ff15afc0ad78a67b79f35" } } ``` Whitelist/Revoke via eth_sendRawTransaction Whitelisting and revoking keys is done by sending a signed Ethereum transaction to the sentinel address 0x1000000000000000000000000000000000000006 via eth_sendRawTransaction. The transaction is intercepted before pool submission and never enters the mempool or gets executed on-chain. Transaction requirements: - sender must be the governance address (read from the protocol params contract) - to must be 0x1000000000000000000000000000000000000006 - value must be 0 - calldata must ABI-encode either: - whitelistKey(address target, uint64 expiresAt) — adds an address to the whitelist until the given Unix timestamp - revokeKey(address target) — removes an address from the whitelist The call returns the transaction hash on success. Transactions from non-governance signers targeting the sentinel address are rejected with an RPC error. Ops RPC Server A new RPC server is added for authorized storage reads because the auth RPC server only supports JWT authentication and cannot be easily extended to support additional authentication methods. This new RPC server uses the ops namespace (short for operations). The admin namespace is already used. The ops RPC server is deactivated by default and can be activated via the --ops.enable CLI flag. The address defaults to 127.0.0.1 and can be set via --ops.addr; the port defaults to 8552 and can be set via --ops.port. ops_getStorageAt Request format: `{"jsonrpc":"2.0","method":"ops_getStorageAt","params":["0x<address>","0x<slot>","latest"],"id":1}` Authorized by a signature from a whitelisted key. The signature must be EIP-712-structured over the request body and nonce. Signature and nonce are stored in the X-Signature and X-Nonce HTTP headers, respectively. ops_getNonce Request format: `{"jsonrpc":"2.0","method":"ops_getNonce","params":["0x<signer_address>"],"id":1}` Authorized by a signature from a whitelisted key. The signature must be EIP-712-structured over the request body (nonce is set to the empty string). Signature is stored in the X-Signature HTTP header.
## Summary - Adds `lefthook.yml` with git hooks matching CI checks in `seismic.yml`: - **pre-commit**: `cargo +nightly fmt --all` (auto-formats code) - **pre-push**: strict clippy on seismic crates (same flags as CI), `typos` spell check ## Setup After merging, each developer needs to run `lefthook install` once in their local clone. Co-authored-by: henry-ai <henrymbaldwin+ai@proton.me>
Co-authored-by: drappi-ai <christiandrappi+ai@gmail.com>
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.
No description provided.