Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions CHANGELOG.sf.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## v1.2.0-fh

### Added

* Added Firehose tracing-regression coverage for Base transactions: a prestate-driven test (block
invariants + JSON projection golden) plus an end-to-end `base-system-tests` integration test
tracing a B-20 precompile transfer. The chain-agnostic capture / invariants / projection / golden
framework lives in the shared `firehose-tracer-test` crate (`evm-firehose-tracer-rs` `5.3.0`).

### Changed

* Bumped base to `v1.2.0`.
Expand All @@ -12,11 +19,10 @@

### Fixed

* Regenerated the stale `base-firehose-tests` `nop_transfer` golden block. It had not been refreshed
since it was created against reth `v1.11.4-fh`, so it still recorded `gas_limit: 30000000` for the
EIP-4788 beacon-roots system call; the current tracer reports `31566720`. The mismatch was already
present in `v1.1.1-fh-1` and is unrelated to the `v1.2.0` bump — verified by re-running the test
on the pre-merge tree. No other field of the captured block changed.
* Replaced the stale `base-firehose-tests` `nop_transfer` full-protobuf golden with a JSON
projection plus property invariants. The full-block golden recorded `gas_limit: 30000000` for the
EIP-4788 beacon-roots system call while the current tracer reports `31566720`; the projection
excludes volatile fields like gas, so it no longer rots on such changes.

### Notes

Expand Down
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ Use structured tracing instead of interpolated strings. Always use key=value fie
Keep unit tests colocated with their implementation. Do not introduce standalone `tests.rs` modules for unit tests; define tests in the same `.rs` implementation file/module inside a `#[cfg(test)] mod tests { ... }` block.

`#[cfg(test)] mod tests { ... }` must always be placed at the end of the file, after all non-test code.

## Firehose tracing tests

The tracing-regression framework (capture, invariants, JSON projection, golden) is chain-agnostic and lives in the `firehose-tracer-test` crate of `evm-firehose-tracer-rs`; `base-firehose-tests` re-exports it and adds the Base bindings (`BaseFirehoseCapture::install`, `run_prestate`). Regenerate any golden with `GOLDEN_UPDATE=1`. The Docker-backed `base-system-tests --test firehose_b20` must run with `RUSTFLAGS="-C debug-assertions=off"` (reth's `deferred_trie::wait_cloned` debug-asserts from a Rayon worker).
39 changes: 35 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,12 @@ ark-bls12-381 = { version = "0.5.0", default-features = false }
# Firehose tracer (defined by the streamingfast reth fork, firehose/2.x branch).
reth-firehose = { git = "https://github.com/streamingfast/reth.git", tag = "v2.3.0-fh-5" }
reth-firehose-tests = { git = "https://github.com/streamingfast/reth.git", tag = "v2.3.0-fh-5" }
firehose-tracer = "5.2.1"
firehose-tracer = "5.3.0"

[patch.crates-io]
# Hotfix: gate the "mismatch between call logs and receipt logs" panic behind the
# FIREHOSE_TRACER_IGNORE_LOG_MISMATCH env var so it logs and skips instead of crashing.
firehose-tracer = { git = "https://github.com/streamingfast/evm-firehose-tracer-rs.git", tag = "v5.2.2" }
# Shared tracing-regression framework (capture / invariants / projection / golden).
firehose-tracer-test = "5.3.0"

[patch.crates-io]
# SF fork of alloy-evm that routes system calls (EIP-4788, EIP-2935, etc.) through the
# Inspector, so Firehose tracing observes them. Matches the patch in streamingfast/reth
# v2.3.0-fh. See https://github.com/alloy-rs/evm/pull/323 for the upstream PR.
Expand Down
3 changes: 1 addition & 2 deletions crates/execution/firehose-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ base-execution-chainspec.workspace = true
reth-firehose.workspace = true
reth-revm.workspace = true
firehose-tracer.workspace = true
firehose-tracer-test.workspace = true
reth-firehose-tests.workspace = true
reth-primitives-traits.workspace = true

Expand All @@ -36,8 +37,6 @@ revm.workspace = true

# encoding & errors
eyre.workspace = true
prost.workspace = true
serde.workspace = true
serde_json.workspace = true

[[test]]
Expand Down
21 changes: 20 additions & 1 deletion crates/execution/firehose-tests/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
Integration test harness for the Firehose tracer on Base / OP Stack chains.
Base-side bindings for the Firehose tracing-regression framework.

The framework itself — `FirehoseCapture`, `BlockInvariants`, `BlockProjection` / `SymbolTable` /
`VolatilePolicy`, `Golden` — is chain-agnostic and lives in `firehose-tracer-test` (in
`evm-firehose-tracer-rs`). This crate re-exports it and adds the two Base-specific pieces:

- `run_prestate` — replays a hand-written `prestate.json` (genesis + block context + one signed
transaction) through the tracer with no node involved. Fast, hermetic, but the fixture is
hand-maintained.
- `BaseFirehoseCapture::install` — the reth binding: installs the process-wide buffer-backed tracer
(`reth_firehose::init_tracer_with_buffer`) and hands the buffer to `FirehoseCapture`, so a test
driving a real node captures the `FIRE BLOCK` lines it emits.

Assert on the captured `Block` with:

- `BlockInvariants` — content-independent property assertions that never need regenerating.
- `BlockProjection` + `Golden` — a descriptor-driven JSON golden with volatile fields removed by a
`VolatilePolicy` (`none()` for reproducible prestate replays, `live_node()` for system tests).

Regenerate every golden with `GOLDEN_UPDATE=1`.
40 changes: 40 additions & 0 deletions crates/execution/firehose-tests/src/capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Base's reth binding for the shared [`FirehoseCapture`] framework.
//!
//! The capture / invariants / projection / golden machinery lives in `firehose-tracer-test` and is
//! chain-agnostic. Installing the process-wide tracer is the one part that cannot: the
//! `GLOBAL_TRACER` singleton and the `is_tracer_initialized()` gate the live engine path checks
//! (`crates/execution/engine-tree/src/validator.rs`) both live in `reth-firehose`. This module is
//! the thin adapter that installs reth's buffer-backed tracer and hands the buffer to
//! [`FirehoseCapture`].

use firehose_tracer_test::FirehoseCapture;

/// Base-specific installer for the shared Firehose capture framework.
#[derive(Debug)]
pub struct BaseFirehoseCapture;

impl BaseFirehoseCapture {
/// Installs the process-wide buffer-backed tracer and returns a capture handle over it.
///
/// Must be called before any block is validated by the node under test — the traced execution
/// path is gated on `reth_firehose::is_tracer_initialized()`. Panics if a tracer was already
/// installed in this process (the tracer is a process-wide singleton, so a test binary using
/// this holds a single `#[test]`).
///
/// The fork timestamps only affect how block contents are mapped, not whether a block is
/// emitted; `Some(0)` means "active from genesis" and `None` means "never".
pub fn install(
chain_id: u64,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
prague_time: Option<u64>,
) -> FirehoseCapture {
let buffer = reth_firehose::init_tracer_with_buffer(
chain_id,
shanghai_time,
cancun_time,
prague_time,
);
FirehoseCapture::new(buffer)
}
}
9 changes: 8 additions & 1 deletion crates/execution/firehose-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#![doc = include_str!("../README.md")]

mod prestate;
pub use prestate::{assert_block_equals_golden, run_prestate};
pub use prestate::run_prestate;

mod capture;
pub use capture::BaseFirehoseCapture;
// The tracing-regression framework is chain-agnostic and lives in `firehose-tracer-test`.
pub use firehose_tracer_test::{
BlockDiff, BlockInvariants, BlockProjection, FirehoseCapture, Golden, InvariantConfig,
SymbolTable, Violation, VolatilePolicy,
};
pub use reth_firehose_tests::RunOutcome;
6 changes: 2 additions & 4 deletions crates/execution/firehose-tests/src/prestate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ use revm::database::{CacheDB, EmptyDB};
///
/// `case_folder` must contain `prestate.json` (Base/OP-style genesis + block context + EIP-2718
/// encoded signed transaction). The captured `Block` is the protobuf parsed from the single
/// `FIRE BLOCK` line emitted for the executed block; assert against a `.binpb` golden via
/// [`assert_block_equals_golden`].
/// `FIRE BLOCK` line emitted for the executed block; assert against it with `BlockInvariants` and a
/// `BlockProjection` golden (see `tests/prestate.rs`).
pub fn run_prestate(case_folder: &Path) -> eyre::Result<RunOutcome> {
use alloy_consensus::Block;
use base_common_consensus::BaseBlockBody;
Expand Down Expand Up @@ -148,5 +148,3 @@ fn build_op_header(
..Default::default()
}
}

pub use reth_firehose_tests::assert_block_equals_golden;
Binary file not shown.
Loading
Loading