Skip to content

Conversation

@smartprogrammer93
Copy link

@smartprogrammer93 smartprogrammer93 commented Jan 29, 2026

Summary

Implements HTTP subscription support via polling, allowing HTTP providers to participate in block subscriptions alongside WebSocket providers. This addresses issue #23.

Changes

Core Feature (http-subscription feature flag)

  • HttpPollingSubscription: New subscription backend that polls eth_getBlockByNumber("latest") at configurable intervals
  • Block deduplication: Tracks last seen block number to prevent duplicate emissions
  • Seamless integration: Works transparently with existing RobustSubscription API - callers use the same subscribe_blocks() and recv() interface

Builder API

RobustProviderBuilder::new(ws_provider)
    .fallback(http_provider)
    .allow_http_subscriptions(true)  // Enable HTTP polling for subscriptions
    .poll_interval(Duration::from_secs(12))  // Polling frequency
    .build()

Failover Behavior

  • HTTP providers can now participate in subscription failover chains
  • Mixed WS/HTTP failover works correctly (WS → HTTP and HTTP → WS)
  • HTTP reconnection validates provider reachability before claiming success (prevents "reconnecting" to dead providers)
  • Configuration (poll_interval, call_timeout, buffer_capacity) properly propagates during failover

Files Added/Modified

File Description
src/robust_provider/http_subscription.rs New HTTP polling subscription implementation
src/robust_provider/subscription.rs SubscriptionBackend enum, HTTP failover logic
src/robust_provider/builder.rs poll_interval(), allow_http_subscriptions() methods
src/robust_provider/provider.rs HTTP subscription creation in subscribe_blocks()
tests/http_subscription.rs Comprehensive integration tests
tests/rpc_failover.rs RPC failover integration tests

Test Coverage

  • Basic HTTP subscription flow
  • Block deduplication
  • Failover: WS → HTTP, HTTP → WS
  • Timeout-triggered failover with multiple fallbacks
  • Provider exhaustion behavior
  • Configuration propagation from builder
  • HTTP reconnect validation
  • Stream conversion
  • Error handling and recovery

Usage

// Enable the feature
// Cargo.toml: robust-provider = { version = "...", features = ["http-subscription"] }

let provider = RobustProviderBuilder::new(ws_provider)
    .fallback(http_only_provider)
    .allow_http_subscriptions(true)
    .poll_interval(Duration::from_secs(12))
    .subscription_timeout(Duration::from_secs(60))
    .build()
    .await?;

// Use exactly like before - HTTP polling is transparent
let mut subscription = provider.subscribe_blocks().await?;
while let Ok(block) = subscription.recv().await {
    println!("Block {}", block.number);
}

Breaking Changes

None. Feature is behind http-subscription flag and disabled by default.

Closes #23

Implements OpenZeppelin#23 - Support HTTP Subscription

This PR adds the ability for HTTP providers to participate in block
subscriptions via polling, enabling use cases where WebSocket connections
are not available (e.g., behind load balancers).

## Changes

### New Feature (behind `http-subscription` feature flag)
- Add `HttpPollingSubscription` that polls `eth_getBlockByNumber(latest)`
  at configurable intervals
- Add `SubscriptionBackend` enum to handle both WebSocket and HTTP backends
- Add `poll_interval()` and `allow_http_subscriptions()` builder methods
- Seamless failover between mixed WS/HTTP provider chains

### Files
- `src/robust_provider/http_subscription.rs` - New HTTP polling module
- `src/robust_provider/subscription.rs` - Unified backend handling
- `src/robust_provider/builder.rs` - New configuration options
- `src/robust_provider/provider.rs` - Updated subscribe_blocks()
- `Cargo.toml` - Added `http-subscription` feature flag

## Usage

```rust
let robust = RobustProviderBuilder::new(http_provider)
    .allow_http_subscriptions(true)
    .poll_interval(Duration::from_secs(12))
    .build()
    .await?;

let mut sub = robust.subscribe_blocks().await?;
```

## Trade-offs (documented)
- Latency: up to `poll_interval` delay for block detection
- RPC Load: one call per `poll_interval`
- Feature-gated to ensure explicit opt-in

Closes OpenZeppelin#23
@smartprogrammer93 smartprogrammer93 marked this pull request as draft January 29, 2026 14:14
Add comprehensive integration tests in tests/http_subscription.rs:

- test_http_subscription_basic_flow
- test_http_subscription_multiple_blocks
- test_http_subscription_as_stream
- test_failover_from_ws_to_http
- test_failover_from_http_to_ws
- test_mixed_provider_chain_failover
- test_http_reconnects_to_ws_primary
- test_http_only_no_ws_providers
- test_http_subscription_disabled_falls_back_to_ws
- test_custom_poll_interval

All tests gated behind #[cfg(feature = "http-subscription")]
Audit findings addressed:

Unit tests (http_subscription.rs):
- Improved test_http_polling_deduplication with better verification
- Renamed test_http_polling_handles_drop → test_http_polling_stops_on_drop
  with clearer verification logic
- Added test_http_subscription_error_types for all error variants
- Added test_http_polling_close_method for close() functionality

Integration tests (tests/http_subscription.rs) - rewritten:
- Removed broken test_http_reconnects_to_ws_primary (was meaningless)
- Removed flawed test_custom_poll_interval, replaced with
  test_poll_interval_is_respected (measures correctly)
- Renamed tests for clarity on what they actually verify
- Added test_http_disabled_no_ws_fails (negative test case)
- Added test_all_providers_fail_returns_error (error handling)
- Added test_http_subscription_survives_temporary_errors
- Added test_http_polling_deduplication (integration level)
- Fixed failover tests to verify behavior correctly
- Removed fragile 'pre-mine to distinguish providers' hacks

Test count: 73 total (19 unit + 12 http integration + 24 subscription + 18 eth)
Tests verify that RPC calls (not just subscriptions) properly:
- Failover to fallback providers when primary dies
- Cycle through multiple fallbacks
- Return errors when all providers exhausted
- Don't retry non-retryable errors (BlockNotFound)
- Complete within bounded time when providers unavailable
- Work correctly for various RPC methods (get_accounts, get_balance, get_block)
Fixes two bugs in HTTP subscription handling:

1. http_config now uses configured values from RobustProviderBuilder
   instead of defaults when a WebSocket subscription is created first.
   This ensures poll_interval, call_timeout, and buffer_capacity are
   respected when failing over to HTTP.

2. HTTP reconnection now validates the provider is reachable before
   claiming success. Uses a short 50ms timeout to quickly fail and
   not block the failover process.

Also fixes test timing in test_failover_http_to_ws_on_provider_death
to mine before subscription timeout instead of after.

Adds two new tests:
- test_poll_interval_propagated_from_builder: verifies config propagation
- test_http_reconnect_validates_provider: verifies reconnect validation
@smartprogrammer93 smartprogrammer93 force-pushed the feat/http-subscription branch 2 times, most recently from f94c84d to b6001af Compare January 29, 2026 15:55
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.

Support HTTP Subscription

2 participants