Skip to content

Conversation

@niran
Copy link
Contributor

@niran niran commented Jan 11, 2026

Summary

  • Adds flashblocks-e2e binary for end-to-end regression testing of flashblocks RPC
  • Creates testing/e2e library crate with reusable test infrastructure
  • Includes 22 tests across 7 categories: blocks, call, receipts, logs, sanity, metering, contracts

Architecture

bin/flashblocks-e2e/     # Minimal CLI shim
testing/e2e/             # Reusable library
├── client.rs            # TestClient for RPC interactions
├── harness.rs           # FlashblockHarness for pending state testing
├── types.rs             # MeterBundle*, Flashblock* types
├── runner.rs            # Test execution + output formatting
└── tests/               # Test definitions

Usage

# Run all tests
flashblocks-e2e --rpc-url https://... --flashblocks-ws-url wss://...

# List tests
flashblocks-e2e --list

# Filter tests
flashblocks-e2e --filter "flashblock*"

# JSON output for CI
flashblocks-e2e --format json

Test plan

  • cargo check -p base-e2e -p flashblocks-e2e
  • cargo clippy -p base-e2e -p flashblocks-e2e -- -D warnings
  • Verified against live Base mainnet dev node (14/14 runnable tests pass)

Port the flashblocks-e2e end-to-end testing tool with a reusable library
architecture:

- bin/flashblocks-e2e/: minimal CLI shim (~70 lines)
- testing/e2e/: reusable library with TestClient, FlashblockHarness,
  test runner, and 22 tests across 7 categories

Test categories: blocks, call, receipts, logs, sanity, metering, contracts
@cb-heimdall
Copy link
Collaborator

cb-heimdall commented Jan 11, 2026

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

Establish naming pattern where testing crates include "testing" in the name
for clarity.
danyalprout pushed a commit that referenced this pull request Jan 11, 2026
* fix flashblocks timing and tests

* formatting
danyalprout pushed a commit that referenced this pull request Jan 11, 2026
* fix flashblocks timing and tests

* formatting
niran added 2 commits January 11, 2026 17:28
Remove hardcoded recipient addresses from test files. The recipient
must now be provided via --recipient CLI argument, and the tool aborts
if recipient equals sender to prevent accidental self-transfers.
Copy link
Collaborator

@haardikk21 haardikk21 left a comment

Choose a reason for hiding this comment

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

Some comments

Also a question more generally - what's the intention with this CLI? I may have missed the memo on this but is this something we're gonna run manually against dev nodes to try out things or something?

my prev understanding was its aiming to set the stage a bit for automated devnet-style testing of changes per-PR/pre-release, but then I don't really get the need for the CLI and instead have other things in mind that need to be addressed first.

Comment on lines +21 to +31
Test {
name: "get_latest_block".to_string(),
description: Some("Verify we can retrieve the latest block".to_string()),
run: Box::new(|client| Box::pin(test_get_latest_block(client))),
skip_if: None,
},
Test {
name: "get_pending_block".to_string(),
description: Some("Verify we can retrieve the pending block".to_string()),
run: Box::new(|client| Box::pin(test_get_pending_block(client))),
skip_if: None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

non-blocking nit but this seems like the perfect use case for just definining a custom macro to get rid of these duplications throughout this crate

Comment on lines +66 to +74
fn skip_if_no_signer_or_recipient(client: &TestClient) -> Option<String> {
if !client.has_signer() {
Some("No PRIVATE_KEY configured".to_string())
} else if client.recipient().is_none() {
Some("No --recipient configured".to_string())
} else {
None
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

this fn is present across all the different test files. can we just share this somewhere instead?

Comment on lines +138 to +143
let json_str = decode_ws_message(&msg)?;

let flashblock: Flashblock =
serde_json::from_str(&json_str).wrap_err("Failed to parse flashblock message")?;

return Ok(flashblock);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we just use

impl Flashblock {
/// Attempts to decode a flashblock from bytes that may be plain JSON or brotli-compressed JSON.
pub fn try_decode_message(bytes: impl Into<Bytes>) -> Result<Self, FlashblockDecodeError> {
let text = Self::try_parse_message(bytes.into())?;
let payload: FlashblocksPayloadV1 =
serde_json::from_str(&text).map_err(FlashblockDecodeError::PayloadParse)?;
let metadata: Metadata = serde_json::from_value(payload.metadata.clone())
.map_err(FlashblockDecodeError::MetadataParse)?;
Ok(Self {
payload_id: payload.payload_id,
index: payload.index,
base: payload.base,
diff: payload.diff,
metadata,
})
}
or are we avoiding internal dependencies for some reason?

Comment on lines +149 to +183
pub struct FlashblockBase {
/// Base fee per gas.
pub base_fee_per_gas: String,
/// Block number.
pub block_number: String,
/// Block timestamp.
pub timestamp: String,
/// Fee recipient address.
pub fee_recipient: String,
/// Gas limit.
pub gas_limit: String,
/// Parent block hash.
pub parent_hash: String,
}

/// Diff/delta for this flashblock.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlashblockDiff {
/// State root after this flashblock.
pub state_root: String,
/// Receipts root after this flashblock.
pub receipts_root: String,
/// Logs bloom filter.
pub logs_bloom: String,
/// Cumulative gas used.
pub gas_used: String,
/// Block hash (changes with each flashblock).
pub block_hash: String,
/// RLP-encoded transaction hex strings.
pub transactions: Vec<String>,
/// Withdrawals in this flashblock.
#[serde(default)]
pub withdrawals: Vec<serde_json::Value>,
/// Withdrawals root.
#[serde(default)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

these should just be coming from the flashtypes crate

@cb-heimdall
Copy link
Collaborator

Review Error for haardikk21 @ 2026-01-12 06:12:24 UTC
User failed mfa authentication, see go/mfa-help

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.

4 participants