diff --git a/da-indexer/README.md b/da-indexer/README.md index f9e11bca1..ac43c5388 100644 --- a/da-indexer/README.md +++ b/da-indexer/README.md @@ -60,6 +60,7 @@ l2_chain_id = 123 l2_api_url = "http://localhost:3001" l2_blockscout_url = "http://arbitrum.blockscout.com" l1_chain_id = 456 # optional +request_timeout = 30 # optional ``` ## Dev diff --git a/da-indexer/da-indexer-logic/src/celestia/l2_router/arbitrum.rs b/da-indexer/da-indexer-logic/src/celestia/l2_router/arbitrum.rs index da52f24c9..2e4a05db6 100644 --- a/da-indexer/da-indexer-logic/src/celestia/l2_router/arbitrum.rs +++ b/da-indexer/da-indexer-logic/src/celestia/l2_router/arbitrum.rs @@ -1,10 +1,8 @@ -use std::time::Duration; - use super::types::{L2BatchMetadata, L2Config}; use anyhow::Result; use blockscout_display_bytes::Bytes; use chrono::DateTime; -use reqwest::{Client, Url}; +use reqwest::{Client, StatusCode, Url}; use serde::Deserialize; #[derive(Deserialize, Debug)] @@ -32,15 +30,23 @@ pub async fn get_l2_batch( "{}/api/v2/arbitrum/batches/da/celestia/{}/{}", config.l2_api_url, height, commitment, ); - let timeout = Duration::from_secs(5); - let response: L2BatchArbitrum = Client::new() + + let response = Client::new() .get(&query) - .timeout(timeout) + .timeout(config.request_timeout) .send() - .await? - .json() .await?; + if response.status() == StatusCode::NOT_FOUND { + tracing::debug!( + height, + commitment = hex::encode(&commitment), + "l2 batch metadata not found" + ); + return Ok(None); + } + let response: L2BatchArbitrum = response.json().await?; + Ok(Some(L2BatchMetadata { chain_type: super::types::L2Type::Arbitrum, l2_chain_id: config.l2_chain_id, @@ -51,7 +57,7 @@ pub async fn get_l2_batch( l2_blockscout_url: Url::parse(&config.l2_blockscout_url)? .join(&format!("batches/{}", response.number))? .to_string(), - l1_tx_hash: response.commitment_transaction.hash.clone(), + l1_tx_hash: response.commitment_transaction.hash, l1_tx_timestamp: DateTime::parse_from_rfc3339(&response.commitment_transaction.timestamp)? .timestamp() as u64, l1_chain_id: config.l1_chain_id, diff --git a/da-indexer/da-indexer-logic/src/celestia/l2_router/mod.rs b/da-indexer/da-indexer-logic/src/celestia/l2_router/mod.rs index 8acc1b3f7..ecec290a8 100644 --- a/da-indexer/da-indexer-logic/src/celestia/l2_router/mod.rs +++ b/da-indexer/da-indexer-logic/src/celestia/l2_router/mod.rs @@ -42,12 +42,14 @@ impl L2Router { commitment: &[u8], ) -> Result> { let namespace = Bytes::from(namespace.to_vec()).to_string(); - let config = self.routes.get(&namespace); - if config.is_none() { - tracing::debug!("unknown namespace: {}", &namespace); - return Ok(None); - } - let config = config.unwrap(); + let config = { + let config = self.routes.get(&namespace); + if config.is_none() { + tracing::debug!("unknown namespace: {}", &namespace); + return Ok(None); + } + config.unwrap() + }; match config.l2_chain_type { L2Type::Optimism => optimism::get_l2_batch(config, height, commitment).await, diff --git a/da-indexer/da-indexer-logic/src/celestia/l2_router/optimism.rs b/da-indexer/da-indexer-logic/src/celestia/l2_router/optimism.rs index 0c571b16e..915829393 100644 --- a/da-indexer/da-indexer-logic/src/celestia/l2_router/optimism.rs +++ b/da-indexer/da-indexer-logic/src/celestia/l2_router/optimism.rs @@ -1,7 +1,5 @@ -use std::time::Duration; - use super::{types::L2BatchMetadata, L2Config}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use blockscout_display_bytes::Bytes; use chrono::DateTime; use reqwest::{Client, StatusCode, Url}; @@ -38,8 +36,13 @@ pub async fn get_l2_batch( "{}/api/v2/optimism/batches/da/celestia/{}/{}", config.l2_api_url, height, commitment, ); - let timeout = Duration::from_secs(5); - let response = Client::new().get(&query).timeout(timeout).send().await?; + + let response = Client::new() + .get(&query) + .timeout(config.request_timeout) + .send() + .await?; + if response.status() == StatusCode::NOT_FOUND { tracing::debug!( height, @@ -48,16 +51,24 @@ pub async fn get_l2_batch( ); return Ok(None); } - let response: L2BatchOptimism = response.json().await?; + let mut response: L2BatchOptimism = response.json().await?; - let related_blobs = response + let l1_tx_hash = response .blobs .iter() + .find(|blob| blob.commitment == commitment) + .ok_or(anyhow!("l1 transaction hash not found"))? + .l1_transaction_hash + .clone(); + + let related_blobs = response + .blobs + .drain(..) .filter(|blob| blob.commitment != commitment) .map(|blob| super::types::CelestiaBlobId { height: blob.height, - namespace: blob.namespace.clone(), - commitment: blob.commitment.clone(), + namespace: blob.namespace, + commitment: blob.commitment, }) .collect(); @@ -71,7 +82,7 @@ pub async fn get_l2_batch( l2_blockscout_url: Url::parse(&config.l2_blockscout_url)? .join(&format!("batches/{}", response.internal_id))? .to_string(), - l1_tx_hash: response.l1_tx_hashes[0].clone(), + l1_tx_hash, l1_tx_timestamp: DateTime::parse_from_rfc3339(&response.l1_timestamp)?.timestamp() as u64, l1_chain_id: config.l1_chain_id, related_blobs, diff --git a/da-indexer/da-indexer-logic/src/celestia/l2_router/settings.rs b/da-indexer/da-indexer-logic/src/celestia/l2_router/settings.rs index bb4f9eec2..ed3b1ac70 100644 --- a/da-indexer/da-indexer-logic/src/celestia/l2_router/settings.rs +++ b/da-indexer/da-indexer-logic/src/celestia/l2_router/settings.rs @@ -1,7 +1,5 @@ use serde::Deserialize; -use serde_with::serde_as; -#[serde_as] #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct L2RouterSettings { diff --git a/da-indexer/da-indexer-logic/src/celestia/l2_router/types.rs b/da-indexer/da-indexer-logic/src/celestia/l2_router/types.rs index 9d96be5a1..cb6c97ca6 100644 --- a/da-indexer/da-indexer-logic/src/celestia/l2_router/types.rs +++ b/da-indexer/da-indexer-logic/src/celestia/l2_router/types.rs @@ -1,4 +1,7 @@ +use std::time; + use serde::{Deserialize, Serialize}; +use serde_with::serde_as; #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum L2Type { @@ -6,13 +9,22 @@ pub enum L2Type { Arbitrum, } +#[serde_as] #[derive(Serialize, Deserialize, Debug)] +#[serde(deny_unknown_fields)] pub struct L2Config { pub l2_chain_type: L2Type, pub l2_chain_id: u32, pub l2_api_url: String, pub l2_blockscout_url: String, pub l1_chain_id: Option, + #[serde(default = "default_request_timeout")] + #[serde_as(as = "serde_with::DurationSeconds")] + pub request_timeout: time::Duration, +} + +fn default_request_timeout() -> time::Duration { + time::Duration::from_secs(5) } pub struct CelestiaBlobId { diff --git a/da-indexer/da-indexer-logic/src/celestia/tests/l2_router.rs b/da-indexer/da-indexer-logic/src/celestia/tests/l2_router.rs index fdce35f5d..47bcbd32c 100644 --- a/da-indexer/da-indexer-logic/src/celestia/tests/l2_router.rs +++ b/da-indexer/da-indexer-logic/src/celestia/tests/l2_router.rs @@ -2,7 +2,7 @@ use crate::celestia::l2_router::{ types::{L2Config, L2Type}, L2Router, }; -use std::{collections::HashMap, str::FromStr}; +use std::{collections::HashMap, str::FromStr, time}; use blockscout_display_bytes::Bytes; use serde_json::json; @@ -93,6 +93,7 @@ async fn create_test_router() -> L2Router { l2_api_url: mock_server.uri(), l2_blockscout_url: "http://raspberry.blockscout.com".to_string(), l1_chain_id: None, + request_timeout: time::Duration::from_secs(5), }, ); routes.insert( @@ -103,6 +104,7 @@ async fn create_test_router() -> L2Router { l2_api_url: mock_server.uri(), l2_blockscout_url: "http://arbitrum.blockscout.com".to_string(), l1_chain_id: Some(12), + request_timeout: time::Duration::from_secs(5), }, ); diff --git a/da-indexer/da-indexer-server/config/celestia_routes.toml b/da-indexer/da-indexer-server/config/celestia_routes.toml index c701f7c55..16b5736a1 100644 --- a/da-indexer/da-indexer-server/config/celestia_routes.toml +++ b/da-indexer/da-indexer-server/config/celestia_routes.toml @@ -8,4 +8,5 @@ l2_blockscout_url = "http://arbitrum.blockscout.com" l2_chain_type = "Optimism" l2_chain_id = 123420111 l2_api_url = "https://opcelestia-raspberry.gelatoscout.com/" -l2_blockscout_url = "https://opcelestia-raspberry.gelatoscout.com/" \ No newline at end of file +l2_blockscout_url = "https://opcelestia-raspberry.gelatoscout.com/" +request_timeout = 30 \ No newline at end of file diff --git a/da-indexer/da-indexer-server/src/main.rs b/da-indexer/da-indexer-server/src/main.rs index d2966efec..35be411eb 100644 --- a/da-indexer/da-indexer-server/src/main.rs +++ b/da-indexer/da-indexer-server/src/main.rs @@ -17,8 +17,8 @@ async fn main() -> Result<(), anyhow::Error> { let db_connection = match settings.database.clone() { Some(database_settings) => { - let database_url = database_settings.connect.clone().url(); - let mut connect_options = sea_orm::ConnectOptions::new(&database_url); + let database_url = &database_settings.connect.url(); + let mut connect_options = sea_orm::ConnectOptions::new(database_url); connect_options.sqlx_logging_level(tracing::log::LevelFilter::Debug); Some( database::initialize_postgres::( @@ -45,7 +45,7 @@ async fn main() -> Result<(), anyhow::Error> { let db_connection = match settings.database.clone() { Some(database_settings) => Some( database::initialize_postgres::( - &database_settings.connect.clone().url(), + &database_settings.connect.url(), false, false, ) diff --git a/da-indexer/da-indexer-server/src/services/celestia.rs b/da-indexer/da-indexer-server/src/services/celestia.rs index ced40e59c..86dd80cc6 100644 --- a/da-indexer/da-indexer-server/src/services/celestia.rs +++ b/da-indexer/da-indexer-server/src/services/celestia.rs @@ -71,24 +71,22 @@ impl Celestia for CelestiaService { let commitment = bytes_from_hex_or_base64(&inner.commitment, "commitment")?; let namespace = bytes_from_hex_or_base64(&inner.namespace, "namespace")?; - let l2_batch_metadata = l2_router + let mut l2_batch_metadata = l2_router .get_l2_batch_metadata(height, &namespace, &commitment) .await .map_err(|err| { tracing::error!(height, namespace = hex::encode(&namespace), commitment = hex::encode(&commitment), error = ?err, "failed to query l2 batch metadata"); Status::internal("failed to query l2 batch metadata") })? - .ok_or_else(|| { - Status::not_found("l2 batch metadata not found") - })?; + .ok_or(Status::not_found("l2 batch metadata not found"))?; let related_blobs = l2_batch_metadata .related_blobs - .iter() + .drain(..) .map(|blob| CelestiaBlobId { height: blob.height, - namespace: blob.namespace.clone(), - commitment: blob.commitment.clone(), + namespace: blob.namespace, + commitment: blob.commitment, }) .collect();