pindexer/
block.rs

1use cometindex::{
2    async_trait,
3    index::{EventBatch, EventBatchContext},
4    sqlx, AppView, PgTransaction,
5};
6use penumbra_sdk_proto::{core::component::sct::v1 as pb, event::ProtoEvent};
7use sqlx::types::chrono::DateTime;
8
9#[derive(Debug)]
10pub struct Block {}
11
12#[async_trait]
13impl AppView for Block {
14    fn name(&self) -> String {
15        "block".to_string()
16    }
17
18    async fn init_chain(
19        &self,
20        dbtx: &mut PgTransaction,
21        _: &serde_json::Value,
22    ) -> Result<(), anyhow::Error> {
23        sqlx::query(
24            // table name is module path + struct name
25            "
26CREATE TABLE IF NOT EXISTS block_details (
27    height BIGINT PRIMARY KEY,
28    root BYTEA NOT NULL,
29    timestamp TIMESTAMPTZ NOT NULL
30);
31",
32        )
33        .execute(dbtx.as_mut())
34        .await?;
35        Ok(())
36    }
37
38    async fn index_batch(
39        &self,
40        dbtx: &mut PgTransaction,
41        batch: EventBatch,
42        _ctx: EventBatchContext,
43    ) -> Result<(), anyhow::Error> {
44        for event in batch.events() {
45            let pe = match pb::EventBlockRoot::from_event(event.as_ref()) {
46                Ok(pe) => pe,
47                Err(_) => continue,
48            };
49            let timestamp = pe.timestamp.unwrap_or_default();
50
51            sqlx::query(
52                "
53            INSERT INTO block_details (height, timestamp, root)
54            VALUES ($1, $2, $3)
55            ",
56            )
57            .bind(i64::try_from(pe.height)?)
58            .bind(DateTime::from_timestamp(
59                timestamp.seconds,
60                u32::try_from(timestamp.nanos)?,
61            ))
62            .bind(pe.root.unwrap().inner)
63            .execute(dbtx.as_mut())
64            .await?;
65        }
66        Ok(())
67    }
68}