Skip to content

Use base fee fallback in gas price chart#44

Open
pthmas wants to merge 5 commits intomainfrom
pthmas/fix-zero-gas-chart
Open

Use base fee fallback in gas price chart#44
pthmas wants to merge 5 commits intomainfrom
pthmas/fix-zero-gas-chart

Conversation

@pthmas
Copy link
Copy Markdown
Collaborator

@pthmas pthmas commented Mar 31, 2026

Index block base_fee_per_gas so the gas price chart has a protocol-level fallback.
Use average transaction gas price when transactions exist, and base fee when a bucket is empty.

Summary by CodeRabbit

  • New Features

    • Collect and store block base-fee-per-gas values for richer block data.
  • Improvements

    • Gas price chart preserves empty buckets (shows null) and combines transaction/base-fee averages with transaction-preference fallback.
    • Chart tooltips and types now handle null/unknown gas-price values (displaying an em dash).
  • Chores

    • Removed several faucet-related environment variables from local service config.
  • Tests

    • Added unit tests covering preference, fallback, and empty-bucket gas-price cases.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds nullable block-level base_fee_per_gas (DB, indexer, COPY pipeline, types); preserves nullable per-bucket gas-price results by making GasPricePoint.avg_gas_price optional and resolving tx→block fallback in Rust; frontend types and tooltip formatting updated for nullable values.

Changes

Cohort / File(s) Summary
Database Schema & Core Block Type
backend/migrations/20260407000002_add_blocks_base_fee_per_gas.sql, backend/crates/atlas-common/src/types.rs
Add blocks.base_fee_per_gas NUMERIC(78,0) and map to Block.base_fee_per_gas: Option<String>; update BLOCK_COLUMNS.
Indexer & Batch Processing
backend/crates/atlas-server/src/indexer/indexer.rs, backend/crates/atlas-server/src/indexer/batch.rs, backend/crates/atlas-server/src/indexer/copy.rs
Collect and propagate base_fee_per_gas into BlockBatch.b_base_fee_per_gas, include column in COPY input and INSERT/ON CONFLICT, and assert vector length sync during materialization.
Block Query Handlers
backend/crates/atlas-server/src/api/handlers/blocks.rs, backend/crates/atlas-server/src/api/handlers/search.rs
Switch SELECT projections to use atlas_common::BLOCK_COLUMNS (now includes base_fee_per_gas) instead of hard-coded column lists.
Gas Price Stats Handler
backend/crates/atlas-server/src/api/handlers/stats.rs
SQL now returns per-bucket nullable aggregates from transactions and blocks; GasPricePoint.avg_gas_priceOption<f64>; add resolve_avg_gas_price(tx, block) to prefer tx avg, fallback to block base fee, or None; tests added for preference/fallback/empty.
Frontend Types & Chart Data
frontend/src/types/index.ts, frontend/src/api/chartData.ts
Add optional `base_fee_per_gas?: string
Frontend Chart UI
frontend/src/pages/StatusPage.tsx
Make formatGwei null-safe (accepts `number
Test Fixtures
backend/crates/atlas-server/src/api/handlers/sse.rs, backend/crates/atlas-server/src/api/handlers/status.rs, backend/crates/atlas-server/src/head.rs, .../indexer/batch.rs tests
Populate sample_block fixtures and tests with base_fee_per_gas: Some("1000000000") and assert propagation through batch/indexer paths.
Dev/Infra
docker-compose.yml
Remove three faucet env vars (FAUCET_PRIVATE_KEY, FAUCET_AMOUNT, FAUCET_COOLDOWN_MINUTES) from the atlas-server service environment.

Sequence Diagram(s)

sequenceDiagram
  participant Indexer as Indexer
  participant DB as Database
  participant API as Atlas API
  participant FE as Frontend

  rect rgba(200,220,255,0.5)
  Indexer->>DB: INSERT/UPDATE blocks (include base_fee_per_gas)
  end
  Note right of DB: blocks.base_fee_per_gas stored (nullable)

  FE->>API: GET /stats/gas-price (chart)
  API->>DB: Run bucketed SQL\n(tx.avg_gas_price, block.avg_base_fee_per_gas)
  DB-->>API: Return bucket rows with nullable aggregates
  API->>API: resolve_avg_gas_price(tx_avg, block_avg)\n(prefers tx, then block, else null)
  API-->>FE: JSON with avg_gas_price (nullable)
  FE->>FE: formatGwei(value:number|null)\nshow '—' for null/NaN
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • tac0turtle

Poem

🐰 I nibble bytes where base fees hide,
From indexer to chart they softly glide,
Tx-first whispers, blocks fill the seam,
Nulls wear an em dash — a tidy dream,
Hoppity-hop, the atlas keeps its stride.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Use base fee fallback in gas price chart' accurately describes the main change: making the gas price chart use block base fees as a fallback when transaction data is unavailable, avoiding zero values.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pthmas/fix-zero-gas-chart

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/crates/atlas-server/src/api/handlers/stats.rs (1)

231-266: Consider adding a unit test for nullable serialization.

The existing tests cover Window enum methods but don't validate the new nullable avg_gas_price behavior. A simple serialization test would help ensure Option<f64> serializes correctly to JSON null.

📝 Example test to add
+    #[test]
+    fn gas_price_point_serializes_null() {
+        let point = GasPricePoint {
+            bucket: "2024-01-01T00:00:00Z".to_string(),
+            avg_gas_price: None,
+        };
+        let json = serde_json::to_string(&point).unwrap();
+        assert!(json.contains(r#""avg_gas_price":null"#));
+    }

As per coding guidelines: "Add unit tests for new logic in a #[cfg(test)] mod tests block in the same file".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/src/api/handlers/stats.rs` around lines 231 -
266, Add a unit test in the existing #[cfg(test)] mod tests that verifies
nullable avg_gas_price serializes to JSON null and Some(f64) serializes to a
numeric value: create a small #[derive(Serialize, Deserialize, PartialEq,
Debug)] temp struct with an avg_gas_price: Option<f64> field inside the tests
module, use serde_json::to_string (and optionally from_str) to assert that None
-> "null" for that field in the JSON and Some(1.23) -> numeric 1.23, and place
the test alongside the existing Window tests so it runs with cargo test;
reference avg_gas_price, serde_json::to_string, and the tests module when
locating where to add it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/crates/atlas-server/src/api/handlers/stats.rs`:
- Around line 231-266: Add a unit test in the existing #[cfg(test)] mod tests
that verifies nullable avg_gas_price serializes to JSON null and Some(f64)
serializes to a numeric value: create a small #[derive(Serialize, Deserialize,
PartialEq, Debug)] temp struct with an avg_gas_price: Option<f64> field inside
the tests module, use serde_json::to_string (and optionally from_str) to assert
that None -> "null" for that field in the JSON and Some(1.23) -> numeric 1.23,
and place the test alongside the existing Window tests so it runs with cargo
test; reference avg_gas_price, serde_json::to_string, and the tests module when
locating where to add it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b221d7f7-91af-4127-820a-abd7cf2f17e0

📥 Commits

Reviewing files that changed from the base of the PR and between 1f86eb2 and 6ee6edb.

📒 Files selected for processing (4)
  • backend/crates/atlas-server/src/api/handlers/stats.rs
  • frontend/src/api/chartData.ts
  • frontend/src/hooks/useChartData.ts
  • frontend/src/pages/StatusPage.tsx

@pthmas pthmas changed the title Preserve gas price chart across empty buckets fix: Preserve gas price chart across empty buckets Mar 31, 2026
@tac0turtle
Copy link
Copy Markdown
Contributor

can you share a screen shot of before and after?

@pthmas pthmas changed the title fix: Preserve gas price chart across empty buckets Use base fee fallback in gas price chart Apr 7, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/crates/atlas-server/src/api/handlers/stats.rs (1)

78-81: Breaking change to API response type — verify frontend alignment.

Changing avg_gas_price from f64 to Option<f64> means the JSON field can now be null instead of always a number. The AI summary indicates frontend changes handle this, but ensure consumers are updated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/src/api/handlers/stats.rs` around lines 78 - 81,
You changed the API shape by making GasPricePoint.avg_gas_price an Option<f64>,
which allows nulls; either revert it to f64 to preserve the original contract or
if you intend nulls, update all consumers and API metadata: update the
OpenAPI/Swagger spec and docs, modify frontend code to handle null avg_gas_price
(and related parsing/formatting), and add appropriate serde behavior on the
GasPricePoint type (e.g., default/skip_serializing_if) so serialization is
explicit—ensure GasPricePoint and avg_gas_price are updated consistently across
server, docs, and frontend.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/crates/atlas-server/src/api/handlers/stats.rs`:
- Around line 78-81: You changed the API shape by making
GasPricePoint.avg_gas_price an Option<f64>, which allows nulls; either revert it
to f64 to preserve the original contract or if you intend nulls, update all
consumers and API metadata: update the OpenAPI/Swagger spec and docs, modify
frontend code to handle null avg_gas_price (and related parsing/formatting), and
add appropriate serde behavior on the GasPricePoint type (e.g.,
default/skip_serializing_if) so serialization is explicit—ensure GasPricePoint
and avg_gas_price are updated consistently across server, docs, and frontend.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0a2ddaf-58b9-406b-8229-b8b85f99e857

📥 Commits

Reviewing files that changed from the base of the PR and between 6ee6edb and a737dd4.

📒 Files selected for processing (12)
  • backend/crates/atlas-common/src/types.rs
  • backend/crates/atlas-server/src/api/handlers/blocks.rs
  • backend/crates/atlas-server/src/api/handlers/search.rs
  • backend/crates/atlas-server/src/api/handlers/sse.rs
  • backend/crates/atlas-server/src/api/handlers/stats.rs
  • backend/crates/atlas-server/src/api/handlers/status.rs
  • backend/crates/atlas-server/src/head.rs
  • backend/crates/atlas-server/src/indexer/batch.rs
  • backend/crates/atlas-server/src/indexer/copy.rs
  • backend/crates/atlas-server/src/indexer/indexer.rs
  • backend/migrations/20260407000002_add_blocks_base_fee_per_gas.sql
  • frontend/src/types/index.ts
✅ Files skipped from review due to trivial changes (5)
  • backend/crates/atlas-server/src/api/handlers/sse.rs
  • backend/crates/atlas-server/src/api/handlers/status.rs
  • frontend/src/types/index.ts
  • backend/migrations/20260407000002_add_blocks_base_fee_per_gas.sql
  • backend/crates/atlas-server/src/head.rs

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/crates/atlas-server/src/api/handlers/stats.rs (1)

290-303: Consider adding test for Some/None case.

The tests cover preference, fallback, and empty-bucket scenarios well. For completeness, consider adding a test for the case where transaction average exists but block base fee is None:

🧪 Proposed additional test
     #[test]
     fn resolve_avg_gas_price_returns_none_when_bucket_is_empty() {
         assert_eq!(resolve_avg_gas_price(None, None), None);
     }
+
+    #[test]
+    fn resolve_avg_gas_price_uses_tx_avg_when_no_block_base_fee() {
+        assert_eq!(resolve_avg_gas_price(Some(42.0), None), Some(42.0));
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/src/api/handlers/stats.rs` around lines 290 -
303, Add a unit test for resolve_avg_gas_price that verifies when the
transaction average is Some(value) and the block base fee is None the function
still returns the transaction average; locate the test module containing
resolve_avg_gas_price (existing tests like
resolve_avg_gas_price_prefers_transaction_average) and add a new test function
(e.g., resolve_avg_gas_price_with_tx_some_block_none) that asserts
resolve_avg_gas_price(Some(42.0), None) == Some(42.0).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/crates/atlas-server/src/api/handlers/stats.rs`:
- Around line 290-303: Add a unit test for resolve_avg_gas_price that verifies
when the transaction average is Some(value) and the block base fee is None the
function still returns the transaction average; locate the test module
containing resolve_avg_gas_price (existing tests like
resolve_avg_gas_price_prefers_transaction_average) and add a new test function
(e.g., resolve_avg_gas_price_with_tx_some_block_none) that asserts
resolve_avg_gas_price(Some(42.0), None) == Some(42.0).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4007c168-7658-4956-bc6f-1b2b9157c778

📥 Commits

Reviewing files that changed from the base of the PR and between 2977680 and 5c2e357.

📒 Files selected for processing (2)
  • backend/crates/atlas-server/src/api/handlers/stats.rs
  • docker-compose.yml
💤 Files with no reviewable changes (1)
  • docker-compose.yml

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/crates/atlas-server/src/api/handlers/stats.rs (1)

288-302: Good test coverage for the new resolution logic.

The three test cases appropriately cover:

  • Transaction average takes precedence when both are present
  • Falls back to base fee when transaction average is missing
  • Returns None when both sources are empty

Consider adding an edge case test for when transaction average is Some(0.0) to verify it's still preferred over a non-zero base fee (since Some(0.0) is truthy in the .or() chain).

🧪 Optional: edge case test for zero transaction average
     #[test]
     fn resolve_avg_gas_price_returns_none_when_bucket_is_empty() {
         assert_eq!(resolve_avg_gas_price(None, None), None);
     }
+
+    #[test]
+    fn resolve_avg_gas_price_prefers_zero_tx_avg_over_base_fee() {
+        // Some(0.0) is still a valid transaction average and should be preferred
+        assert_eq!(resolve_avg_gas_price(Some(0.0), Some(100.0)), Some(0.0));
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/crates/atlas-server/src/api/handlers/stats.rs` around lines 288 -
302, Add an edge-case unit test for resolve_avg_gas_price that verifies a
transaction average of Some(0.0) is preferred over a non-zero base fee (e.g.,
resolve_avg_gas_price(Some(0.0), Some(7.0)) returns Some(0.0)); locate the tests
near the existing resolve_avg_gas_price tests and add a descriptive test
function name like resolve_avg_gas_price_prefers_zero_transaction_average to
ensure the function's Some(0.0) value isn't incorrectly treated as absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/crates/atlas-server/src/api/handlers/stats.rs`:
- Around line 288-302: Add an edge-case unit test for resolve_avg_gas_price that
verifies a transaction average of Some(0.0) is preferred over a non-zero base
fee (e.g., resolve_avg_gas_price(Some(0.0), Some(7.0)) returns Some(0.0));
locate the tests near the existing resolve_avg_gas_price tests and add a
descriptive test function name like
resolve_avg_gas_price_prefers_zero_transaction_average to ensure the function's
Some(0.0) value isn't incorrectly treated as absent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 743a1512-4124-4e76-85ae-ffaa14d732e5

📥 Commits

Reviewing files that changed from the base of the PR and between 5c2e357 and 6b25def.

📒 Files selected for processing (1)
  • backend/crates/atlas-server/src/api/handlers/stats.rs

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