use std::time::{Duration, Instant};
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use alloy_primitives::BlockNumber;
use async_trait::async_trait;
use roxy_types::RoxyError;
#[derive(Debug, Clone, Copy)]
pub enum HealthStatus {
Healthy,
Degraded {
latency_ema: Duration,
},
Unhealthy {
error_rate: f64,
},
Banned {
until: Instant,
},
}
#[async_trait]
pub trait Backend: Send + Sync + 'static {
fn name(&self) -> &str;
fn rpc_url(&self) -> &str;
async fn forward(&self, request: RequestPacket) -> Result<ResponsePacket, RoxyError>;
fn health_status(&self) -> HealthStatus;
fn latency_ema(&self) -> Duration;
fn is_healthy(&self) -> bool {
matches!(self.health_status(), HealthStatus::Healthy | HealthStatus::Degraded { .. })
}
}
pub trait HealthTracker: Send + Sync {
fn record(&mut self, duration: Duration, success: bool);
fn latency_ema(&self) -> Duration;
fn error_rate(&self) -> f64;
fn status(&self) -> HealthStatus;
}
pub trait ConsensusTracker: Send + Sync {
fn update(&mut self, backend: &str, height: BlockNumber);
fn latest(&self) -> BlockNumber;
fn safe(&self) -> BlockNumber;
fn finalized(&self) -> BlockNumber;
}