Skip to content

Conversation

@tonatoz
Copy link
Contributor

@tonatoz tonatoz commented Jan 14, 2026

Solana Head Detection: slotSubscribe vs blockSubscribe

Summary

This PR replaces the expensive blockSubscribe WebSocket subscription with the lightweight slotSubscribe approach for Solana head detection. The change reduces WebSocket bandwidth by 95% while maintaining the same real-time performance.


Problem

The blockSubscribe API has significant drawbacks:

  • High bandwidth: ~1KB per notification (full block data)
  • Unstable API: Requires --rpc-pubsub-enable-block-subscription node flag
  • Limited support: Not available on most RPC providers (premium tier only)

Solution

Use slotSubscribe with throttled getBlockHeight HTTP calls:

  • ~50 bytes per notification (only slot/parent/root numbers)
  • Stable API: No special flags required
  • Universal support: Works with all Solana RPC providers
  • Throttled HTTP calls: Every 5 slots (~20% of slot notifications)

Benchmark Results

Synthetic Benchmark (100 slots)

Metric blockSubscribe slotSubscribe
WS messages 100 100
HTTP calls 0 20
Head updates 100 100
Processing time 3728ms 124ms

Real Production Test (Solana Mainnet, ~11 minutes each)

Metric blockSubscribe slotSubscribe
Test duration 663 sec 682 sec
WS messages 1677 1723
HTTP calls 3 370
Head updates 1678 1726
Errors 0 0
WS rate 2.53/sec 2.53/sec
HTTP rate 0.00/sec 0.54/sec

Daily Extrapolation (24 hours)

Metric blockSubscribe slotSubscribe Winner
WS payload/day ~217 MB ~10.8 MB slotSubscribe (95% less)
HTTP calls/day ~3 ~46,656 blockSubscribe
HTTP bandwidth/day ~0 ~4.7 MB blockSubscribe
Total bandwidth/day ~217 MB ~15.5 MB slotSubscribe (93% less)
API stability Unstable Stable slotSubscribe
Provider compatibility Limited Universal slotSubscribe

Implementation Details

slotSubscribe Notification Format

{"slot": 112301554, "parent": 112301553, "root": 112301500}

~50 bytes per notification

Throttling Logic

  • Check actual block height via HTTP every 5 slots
  • Between checks, use cached height value
  • On HTTP error, fallback to cached height or use slot as height

Synthetic Hash

Since slotSubscribe doesn't provide block hash, we generate a deterministic synthetic hash from slot:

val syntheticHash = BlockId.from(ByteBuffer.allocate(32).putLong(slot).array())

This ensures ForkChoice deduplication works correctly.


Conclusion

slotSubscribe is the recommended approach because:

  1. 93% less total bandwidth (15.5 MB vs 217 MB per day)
  2. Stable API - no special node flags required
  3. Universal provider support - works with all Solana RPC providers
  4. Identical head update rate - same real-time performance
  5. Zero errors in production testing

The trade-off of ~46K HTTP calls/day is acceptable:

  • Each call is lightweight (~100 bytes response)
  • Total HTTP bandwidth is only ~4.7 MB/day
  • HTTP calls are throttled (every 5 slots, not every slot)

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates Solana head detection from the expensive blockSubscribe WebSocket API to the lightweight slotSubscribe API. The change significantly reduces bandwidth usage (by ~93% according to benchmarks) while maintaining real-time performance through throttled HTTP calls to retrieve actual block heights.

Changes:

  • Replaced blockSubscribe/blockUnsubscribe with slotSubscribe/slotUnsubscribe for WebSocket subscriptions
  • Implemented throttled HTTP calls (every 5 slots) to retrieve actual block heights via getBlockHeight
  • Introduced synthetic hash generation based on slot numbers for ForkChoice deduplication
  • Added caching mechanism for block heights per upstream to minimize HTTP calls
  • Simplified data models: replaced SolanaWrapper/SolanaContext/SolanaResult with SolanaSlotNotification

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
src/main/kotlin/io/emeraldpay/dshackle/upstream/solana/SolanaChainSpecific.kt Core implementation of slotSubscribe-based head detection with throttled HTTP calls, synthetic hash generation, and per-upstream caching
src/test/kotlin/io/emeraldpay/dshackle/upstream/solana/SolanaChainSpecificTest.kt Comprehensive test coverage for slot parsing, throttling logic, synthetic hashes, and error handling scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tonatoz tonatoz requested a review from a10zn8 January 14, 2026 14:37
@tonatoz tonatoz force-pushed the solana-new-head branch 2 times, most recently from 0783c77 to 7fa4e77 Compare January 14, 2026 14:47
… strategy, remove BlockSubscribe tests, and enhance caching logic. Delete SolanaStrategyBenchmark for performance comparison.
Replace two separate RPC calls (getSlot + getBlockHeight) with a single getEpochInfo call that returns both absoluteSlot and blockHeight
…imistic height estimation and improve error handling for RPC failures. Update tests to validate new behavior.
@tonatoz tonatoz requested a review from a10zn8 January 16, 2026 12:09
…Height with getEpochInfo for improved efficiency and accuracy in height estimation. Update logic to handle actual slot and height retrieval.
@tonatoz tonatoz merged commit cd57300 into master Jan 19, 2026
1 check passed
@tonatoz tonatoz deleted the solana-new-head branch January 19, 2026 08:25
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.

3 participants