use super::DEFAULT_RPC_CALL_TIMEOUT;
use alloy::providers::{Provider, ProviderBuilder};
use alloy::rpc::client::RpcClient;
use alloy::transports::{TransportError, TransportFut};
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use std::future::Future;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{Context, Poll};
use std::time::Duration;
#[derive(Clone, Debug, Default)]
struct HangingTransport {
calls: Arc<AtomicUsize>,
}
impl tower::Service<RequestPacket> for HangingTransport {
type Response = ResponsePacket;
type Error = TransportError;
type Future = TransportFut<'static>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: RequestPacket) -> Self::Future {
self.calls.fetch_add(1, Ordering::Relaxed);
Box::pin(std::future::pending())
}
}
pub(crate) fn hanging_provider() -> impl Provider + Clone {
counting_hanging_provider().0
}
pub(crate) fn counting_hanging_provider() -> (impl Provider + Clone, Arc<AtomicUsize>) {
let transport = HangingTransport::default();
let calls = Arc::clone(&transport.calls);
let provider = ProviderBuilder::new().connect_client(RpcClient::new(transport, false));
(provider, calls)
}
const GUARD: Duration = DEFAULT_RPC_CALL_TIMEOUT.saturating_mul(6);
pub(crate) async fn bounded<T>(what: &str, fut: impl Future<Output = T>) -> T {
tokio::time::timeout(GUARD, fut)
.await
.unwrap_or_else(|_elapsed| {
panic!(
"{what} did not complete within {GUARD:?} of virtual time — its \
`chain_events::timed` bound is missing, so a stalled provider \
wedges the watcher tick forever"
)
})
}