90 lines
2.8 KiB
Rust
Raw Normal View History

use std::time::Duration;
use anyhow::{Context as _, Result};
use common::config::BasicAuth;
2026-01-27 08:13:53 +02:00
use futures::{Stream, TryFutureExt};
use log::{info, warn};
2026-01-27 09:46:31 +02:00
pub use logos_blockchain_chain_broadcast_service::BlockInfo;
pub use logos_blockchain_common_http_client::{CommonHttpClient, Error};
2026-01-27 09:46:31 +02:00
pub use logos_blockchain_core::{block::Block, header::HeaderId, mantle::SignedMantleTx};
2026-01-21 11:47:28 -03:00
use reqwest::{Client, Url};
2026-01-27 09:46:31 +02:00
use serde::{Deserialize, Serialize};
2026-01-27 08:13:53 +02:00
use tokio_retry::Retry;
2026-01-07 16:29:37 +02:00
2026-01-27 09:46:31 +02:00
/// Fibonacci backoff retry strategy configuration
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
2026-01-27 09:46:31 +02:00
pub struct BackoffConfig {
pub start_delay_millis: u64,
pub max_retries: usize,
}
2026-01-07 16:29:37 +02:00
impl Default for BackoffConfig {
fn default() -> Self {
Self {
start_delay_millis: 100,
max_retries: 5,
}
}
}
2026-01-08 09:10:00 +02:00
// Simple wrapper
// maybe extend in the future for our purposes
2026-01-29 13:47:39 -03:00
// `Clone` is cheap because `CommonHttpClient` is internally reference counted (`Arc`).
#[derive(Clone)]
2026-01-21 11:47:28 -03:00
pub struct BedrockClient {
http_client: CommonHttpClient,
node_url: Url,
backoff: BackoffConfig,
2026-01-21 11:47:28 -03:00
}
2026-01-07 16:29:37 +02:00
2026-01-08 09:10:00 +02:00
impl BedrockClient {
pub fn new(backoff: BackoffConfig, node_url: Url, auth: Option<BasicAuth>) -> Result<Self> {
info!("Creating Bedrock client with node URL {node_url}");
2026-01-08 09:10:00 +02:00
let client = Client::builder()
2026-01-20 10:26:22 +02:00
//Add more fields if needed
2026-01-08 09:10:00 +02:00
.timeout(std::time::Duration::from_secs(60))
.build()
.context("Failed to build HTTP client")?;
let auth = auth.map(|a| {
logos_blockchain_common_http_client::BasicAuthCredentials::new(a.username, a.password)
});
2026-01-07 16:29:37 +02:00
2026-01-21 11:47:28 -03:00
let http_client = CommonHttpClient::new_with_client(client, auth);
Ok(Self {
http_client,
node_url,
backoff,
2026-01-21 11:47:28 -03:00
})
}
pub async fn post_transaction(&self, tx: SignedMantleTx) -> Result<(), Error> {
Retry::spawn(self.backoff_strategy(), || {
self.http_client
.post_transaction(self.node_url.clone(), tx.clone())
})
.await
2026-01-07 16:29:37 +02:00
}
2026-01-21 14:50:29 +02:00
2026-01-27 08:13:53 +02:00
pub async fn get_lib_stream(&self) -> Result<impl Stream<Item = BlockInfo>, Error> {
self.http_client.get_lib_stream(self.node_url.clone()).await
2026-01-21 14:50:29 +02:00
}
pub async fn get_block_by_id(
&self,
header_id: HeaderId,
) -> Result<Option<Block<SignedMantleTx>>, Error> {
Retry::spawn(self.backoff_strategy(), || {
2026-01-27 08:13:53 +02:00
self.http_client
.get_block_by_id(self.node_url.clone(), header_id)
.inspect_err(|err| warn!("Block fetching failed with error: {err:#}"))
2026-01-21 14:50:29 +02:00
})
.await
}
fn backoff_strategy(&self) -> impl Iterator<Item = Duration> {
tokio_retry::strategy::FibonacciBackoff::from_millis(self.backoff.start_delay_millis)
.take(self.backoff.max_retries)
}
2026-01-07 16:29:37 +02:00
}