125 lines
4.1 KiB
Rust
Raw Normal View History

2026-01-15 15:44:48 +02:00
use std::sync::Arc;
2026-01-27 09:46:31 +02:00
use anyhow::Result;
use bedrock_client::BedrockClient;
2026-01-22 14:44:48 +02:00
use common::{
block::HashableBlockData, communication::indexer::Message,
rpc_primitives::requests::PostIndexerMessageResponse, sequencer_client::SequencerClient,
};
2026-01-21 14:50:29 +02:00
use futures::StreamExt;
use log::info;
2026-01-27 08:13:53 +02:00
use logos_blockchain_core::mantle::{
2026-01-12 15:51:24 +02:00
Op, SignedMantleTx,
ops::channel::{ChannelId, inscribe::InscriptionOp},
};
2026-01-22 14:44:48 +02:00
use tokio::sync::RwLock;
2026-01-09 15:10:38 +02:00
2026-01-22 14:44:48 +02:00
use crate::{config::IndexerConfig, state::IndexerState};
2026-01-12 15:51:24 +02:00
pub mod config;
2026-01-13 15:11:51 +02:00
pub mod state;
2026-01-12 15:51:24 +02:00
2026-01-09 15:10:38 +02:00
pub struct IndexerCore {
2026-01-12 15:51:24 +02:00
pub bedrock_client: BedrockClient,
2026-01-22 14:44:48 +02:00
pub sequencer_client: SequencerClient,
2026-01-12 15:51:24 +02:00
pub config: IndexerConfig,
2026-01-13 15:11:51 +02:00
pub state: IndexerState,
2026-01-09 15:10:38 +02:00
}
impl IndexerCore {
2026-01-22 14:44:48 +02:00
pub fn new(config: IndexerConfig) -> Result<Self> {
2026-01-12 15:51:24 +02:00
Ok(Self {
2026-01-22 14:44:48 +02:00
bedrock_client: BedrockClient::new(
2026-01-27 09:46:31 +02:00
config.bedrock_client_config.auth.clone().map(Into::into),
config.bedrock_client_config.addr.clone(),
2026-01-22 14:44:48 +02:00
)?,
sequencer_client: SequencerClient::new_with_auth(
config.sequencer_client_config.addr.clone(),
config.sequencer_client_config.auth.clone(),
)?,
2026-01-12 15:51:24 +02:00
config,
2026-01-13 15:11:51 +02:00
// No state setup for now, future task.
state: IndexerState {
2026-01-15 15:44:48 +02:00
latest_seen_block: Arc::new(RwLock::new(0)),
2026-01-13 15:11:51 +02:00
},
2026-01-12 15:51:24 +02:00
})
2026-01-09 15:10:38 +02:00
}
2026-01-12 15:51:24 +02:00
pub async fn subscribe_parse_block_stream(&self) -> Result<()> {
2026-01-16 16:15:21 +02:00
loop {
2026-01-27 08:13:53 +02:00
let mut stream_pinned = Box::pin(self.bedrock_client.get_lib_stream().await?);
2026-01-16 16:15:21 +02:00
info!("Block stream joined");
while let Some(block_info) = stream_pinned.next().await {
let header_id = block_info.header_id;
info!("Observed L1 block at height {}", block_info.height);
2026-01-21 14:50:29 +02:00
if let Some(l1_block) = self
.bedrock_client
2026-01-27 09:46:31 +02:00
.get_block_by_id(header_id, &self.config.backoff)
2026-01-21 14:50:29 +02:00
.await?
2026-01-16 16:15:21 +02:00
{
info!("Extracted L1 block at height {}", block_info.height);
2026-01-22 14:44:48 +02:00
let l2_blocks_parsed = parse_blocks(
l1_block.into_transactions().into_iter(),
&self.config.channel_id,
);
2026-01-16 16:15:21 +02:00
for l2_block in l2_blocks_parsed {
// State modification, will be updated in future
{
let mut guard = self.state.latest_seen_block.write().await;
if l2_block.block_id > *guard {
*guard = l2_block.block_id;
}
2026-01-15 15:44:48 +02:00
}
2026-01-16 16:15:21 +02:00
// Sending data into sequencer, may need to be expanded.
2026-01-22 14:44:48 +02:00
let message = Message::L2BlockFinalized {
2026-01-16 16:15:21 +02:00
l2_block_height: l2_block.block_id,
};
2026-01-15 15:44:48 +02:00
2026-01-22 14:44:48 +02:00
let status = self.send_message_to_sequencer(message.clone()).await?;
2026-01-15 15:44:48 +02:00
2026-01-22 14:44:48 +02:00
info!("Sent message {message:#?} to sequencer; status {status:#?}");
2026-01-16 16:15:21 +02:00
}
2026-01-12 15:51:24 +02:00
}
}
2026-01-16 16:15:21 +02:00
// Refetch stream after delay
tokio::time::sleep(std::time::Duration::from_millis(
2026-01-21 14:50:29 +02:00
self.config.resubscribe_interval_millis,
2026-01-16 16:15:21 +02:00
))
.await;
}
2026-01-12 15:51:24 +02:00
}
2026-01-22 14:44:48 +02:00
pub async fn send_message_to_sequencer(
&self,
message: Message,
) -> Result<PostIndexerMessageResponse> {
Ok(self.sequencer_client.post_indexer_message(message).await?)
}
2026-01-12 15:51:24 +02:00
}
2026-01-21 14:50:29 +02:00
fn parse_blocks(
2026-01-12 15:51:24 +02:00
block_txs: impl Iterator<Item = SignedMantleTx>,
decoded_channel_id: &ChannelId,
2026-01-27 09:46:31 +02:00
) -> impl Iterator<Item = HashableBlockData> {
block_txs.flat_map(|tx| {
tx.mantle_tx.ops.into_iter().filter_map(|op| match op {
Op::ChannelInscribe(InscriptionOp {
channel_id,
inscription,
..
}) if channel_id == *decoded_channel_id => {
borsh::from_slice::<HashableBlockData>(&inscription).ok()
}
_ => None,
2026-01-12 15:51:24 +02:00
})
2026-01-27 09:46:31 +02:00
})
2026-01-12 15:51:24 +02:00
}