Skip to content

feat: implement getEpochInfo RPC method - #30

Open
jenish-25 wants to merge 6 commits into
solana-rpc:mainfrom
jenish-25:feat/get-epoch-info
Open

feat: implement getEpochInfo RPC method#30
jenish-25 wants to merge 6 commits into
solana-rpc:mainfrom
jenish-25:feat/get-epoch-info

Conversation

@jenish-25

Copy link
Copy Markdown

Closes #28.

Implements the standard Solana getEpochInfo method. It's commonly used by wallets/explorers to show epoch progress, and most of the data is already available in the codebase.

Approach

The handler resolves a single ClickHouse context slot and derives every field from that one slot, so the response is a consistent snapshot:

  • absoluteSlot, blockHeight, transactionCount reuse the existing resolution paths (latest_slot_cache, latest_block_height_cache.get_or_refresh, clickhouse.get_transaction_count_by_slot).
  • epoch, slotIndex, slotsInEpoch are computed from DEFAULT_SLOTS_PER_EPOCH, assuming the default schedule with no warmup — the same assumption the existing getInflationReward code makes.

It accepts the same optional config object as getSlot (commitment + minContextSlot), rejects processed unless the head cache is enabled, applies the minContextSlot check, and forwards ClickHouse query timings via the downstream header like the sibling handlers.

Response shape (no context wrapper):

{
  "absoluteSlot": 0,
  "blockHeight": 0,
  "epoch": 0,
  "slotIndex": 0,
  "slotsInEpoch": 432000,
  "transactionCount": 0
}

Changes

  • handlers/blocks.rs: new handle_get_epoch_info.
  • handlers/types.rs: EpochInfo response struct (camelCase, nullable transactionCount).
  • handlers/mod.rs: dispatch arm + metrics label.
  • tests/mod.rs: param-validation / routing / processed-commitment rejection tests + a serialization test for the wire format.
  • crates/superbank-rpc/README.md: added to the supported-methods and config-object lists.

Testing

  • cargo fmt --all -- --check — clean.
  • cargo clippy -p superbank-rpc --all-targets --locked -- -D warnings — clean (default features).
  • cargo test -p superbank-rpc --locked — passes (292 tests; 5 new).
  • cargo check/tests under --features grpc-head-cache — pass.

Note: the crate's test harness only has an in-memory hook for the latest-slot query, so the added tests cover param validation, routing, commitment handling, and the serialized wire shape rather than an end-to-end value (which needs a live ClickHouse). Happy to extend if there's a preferred pattern for mocking the block-height/transaction-count queries.

Per the issue, this assumes the default epoch schedule (no warmup), consistent with the existing code.

jenish-25 and others added 2 commits June 30, 2026 20:29
Adds the standard Solana getEpochInfo method, which wallets and explorers
use to show epoch progress.

The handler resolves a single ClickHouse context slot and derives every field
from it so the result is a consistent snapshot:
- absoluteSlot, blockHeight and transactionCount reuse the existing
  slot / block-height / transaction-count resolution paths
- epoch, slotIndex and slotsInEpoch are computed from DEFAULT_SLOTS_PER_EPOCH,
  assuming the default schedule with no warmup (matching getInflationReward)

Accepts the same optional config as getSlot (commitment + minContextSlot),
rejects processed unless the head cache is enabled, and forwards ClickHouse
query timings via the downstream header like the sibling handlers.

Closes solana-rpc#28
Comment thread crates/superbank-rpc/src/handlers/blocks.rs
jenish-25 and others added 2 commits July 1, 2026 10:51
getEpochInfo resolved the context slot from latest_slot_cache (always the
finalized ClickHouse slot) and ignored the requested commitment. Under
grpc-head-cache a confirmed request therefore returned finalized data and was
inconsistent with getSlot/getTransactionCount, which serve the newer confirmed
slot from the head cache.

Resolve the slot honoring the commitment by reusing the TransactionCountPlan
overlay used by getTransactionCount: when the head cache holds a newer slot that
meets the commitment, derive absoluteSlot/epoch/slotIndex from it, read
blockHeight from the head cache (the confirmed slot isn't in ClickHouse yet,
following getBlockHeight), and compute transactionCount as the ClickHouse count
before the overlay start plus the head count. With the head cache off,
everything resolves to the finalized ClickHouse slot as before.

Add a grpc-head-cache test asserting a confirmed getEpochInfo resolves the
context slot to the head slot rather than the ClickHouse slot.
@jenish-25
jenish-25 requested a review from Mctursh July 1, 2026 11:15

@Mctursh Mctursh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm🚀

@jenish-25

Copy link
Copy Markdown
Author

@notwedtm

@notwedtm

notwedtm commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Okay, so I've been reviewing this one a bit deeper because it's continuing a bad pattern that I introduced a while ago.

Basically, getEpochInfo computes its epoch fields with plain integer math — epoch = slot / 432000, slotIndex = slot % 432000, slotsInEpoch = 432000 — which hardcodes the assumption that the cluster uses Solana's default epoch schedule with warmup disabled. That's exactly right for mainnet-beta, but on testnet or any cluster whose genesis enables warmup, the early epochs are short (32, 64, … up to 262,144 slots, with normal 432,000-slot epochs only starting at slot 524,256), so every field the method returns is silently wrong there: at slot 1,000,000 real Solana reports epoch 15, while superbank would report epoch 2 with a slotsInEpoch that never varies.

I think the best approach would be to merge this PR in as-is, and then follow up with another PR to fix these to calculate properly for non-mainnet chains.

@Mctursh

Mctursh commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Yeah, this goes wider than getEpochInfo. I hit the same assumption in getEpochSchedule (#36), which hardcodes the mainnet no-warmup schedule. And getInflationReward on main does it too, in two spots (the default-epoch math and the epoch-to-slot bounds). So it's three methods all assuming mainnet, because the RPC layer has no source for the cluster's real schedule.

The design question before any fix: where should that schedule come from? The ingestor already calls get_epoch_schedule() on its RPC client in the bigtable path, it's just not plumbed through to the RPC layer. A config flag, ingest-and-store, or fetch from upstream at startup all seem viable. Any direction the team's leaning?

I'm close to this through #36, so once there's a direction I can take the follow-up across all three.

@notwedtm

notwedtm commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Yeah, this goes wider than getEpochInfo. I hit the same assumption in getEpochSchedule (#36), which hardcodes the mainnet no-warmup schedule. And getInflationReward on main does it too, in two spots (the default-epoch math and the epoch-to-slot bounds). So it's three methods all assuming mainnet, because the RPC layer has no source for the cluster's real schedule.

The design question before any fix: where should that schedule come from? The ingestor already calls get_epoch_schedule() on its RPC client in the bigtable path, it's just not plumbed through to the RPC layer. A config flag, ingest-and-store, or fetch from upstream at startup all seem viable. Any direction the team's leaning?

I'm close to this through #36, so once there's a direction I can take the follow-up across all three.

Agreed!

I think the ingest-and-store pattern for leader schedule is probably the right approach for Superbank given its goals. Since not all sources expose the schedules (or even have them), we'll need to ensure that any methods that rely on them are under a feature flag.

@Mctursh

Mctursh commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Agreed!

I think the ingest-and-store pattern for leader schedule is probably the right approach for Superbank given its goals. Since not all sources expose the schedules (or even have them), we'll need to ensure that any methods that rely on them are under a feature flag.

Thanks, ingest-and-store works for me. I'll write this up as a tracking issue so the design doesn't clutter this PR, and tag you there. Scoping it to the epoch schedule specifically, since that's what the three methods need and there's no leader-schedule method in the repo yet.

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.

feat: implement getEpochInfo standard RPC method

3 participants