use std::sync::Arc;
use anchor_lang::prelude::Pubkey;
use chrono::{DateTime, Utc};
use clap::{Args, Parser};
use data_anchor_api::{CompoundInclusionProof, CustomerElf, RequestStatus, TimeRange};
use data_anchor_client::{BloberIdentifier, DataAnchorClient, DataAnchorClientResult};
use itertools::Itertools;
use serde::Serialize;
use tracing::instrument;
use crate::formatting::CommandOutput;
#[derive(Debug, Parser)]
pub enum IndexerSubCommand {
#[command(visible_alias = "b")]
Blobs(SlotArgs),
#[command(visible_alias = "bl")]
BlobsForBlober {
#[arg(short, long)]
blober: Pubkey,
#[clap(flatten)]
time_args: TimeArgs,
},
#[command(visible_alias = "bp")]
BlobsForPayer {
#[arg(short = 'y', long)]
blob_payer: Pubkey,
#[arg(short = 'm', long)]
network_name: String,
#[clap(flatten)]
time_args: TimeArgs,
},
#[command(visible_alias = "bn")]
BlobsForNetwork {
#[arg(short = 'm', long)]
network_name: String,
#[clap(flatten)]
time_args: TimeArgs,
},
#[command(visible_alias = "ns")]
BlobsForNamespace {
#[arg(short, long)]
namespace: String,
#[arg(long)]
payer_pubkey: Option<Pubkey>,
#[clap(flatten)]
time_args: TimeArgs,
},
#[deprecated(since = "0.4.3", note = "please use `zk-proof` instead")]
#[command(visible_alias = "pb")]
ProofForBlob {
#[arg(short, long)]
blob: Pubkey,
},
#[deprecated(since = "0.4.3", note = "please use `zk-proof` instead")]
#[command(visible_alias = "p", alias = "proofs")]
Proof(SlotArgs),
#[command(visible_alias = "lp")]
ListPayers {
#[arg(short = 'm', long)]
network_name: String,
},
#[command(visible_alias = "zkp", alias = "zk-proofs")]
ZKProof {
#[arg(short, long)]
slot: u64,
#[arg(long, value_enum)]
proof_type: CustomerElf,
},
#[command(visible_alias = "prs")]
ProofRequestStatus {
#[arg(short, long)]
request_id: String,
},
}
#[derive(Debug, Clone, Args)]
pub struct TimeArgs {
#[arg(long, value_parser=DateTime::parse_from_rfc3339)]
pub start: Option<DateTime<Utc>>,
#[arg(long, value_parser=DateTime::parse_from_rfc3339)]
pub end: Option<DateTime<Utc>>,
}
#[derive(Debug, Args)]
pub struct SlotArgs {
pub slot: u64,
}
#[derive(Debug, Serialize)]
pub enum IndexerCommandOutput {
Blobs(Vec<Vec<u8>>),
Proofs(Box<Option<CompoundInclusionProof>>),
ZKProofs(String),
ProofRequestStatus(String, RequestStatus),
Payers(Vec<Pubkey>),
}
impl std::fmt::Display for IndexerCommandOutput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndexerCommandOutput::Blobs(blobs) => {
write!(
f,
"Blobs: [{}]",
blobs.iter().map(hex::encode).collect_vec().join(", ")
)
}
IndexerCommandOutput::Proofs(proof) => {
write!(f, "Proofs: {proof:?}")
}
IndexerCommandOutput::ZKProofs(request_id) => {
write!(
f,
"ZK Proof request ID (use it to check for proof status via `proof-request-status`): {request_id}"
)
}
IndexerCommandOutput::ProofRequestStatus(request_id, status) => {
write!(
f,
"Proof Request Status: Request ID: {request_id}, Status: {status:?}"
)
}
IndexerCommandOutput::Payers(payers) => {
write!(
f,
"Payers: [{}]",
payers
.iter()
.map(|p| p.to_string())
.collect_vec()
.join(", ")
)
}
}
}
}
impl IndexerSubCommand {
#[instrument(skip(client), level = "debug")]
pub async fn run(
&self,
client: Arc<DataAnchorClient>,
identifier: BloberIdentifier,
) -> DataAnchorClientResult<CommandOutput> {
match self {
IndexerSubCommand::Blobs(SlotArgs { slot }) => {
let data = client.get_blobs(*slot, identifier).await?;
Ok(IndexerCommandOutput::Blobs(data.unwrap_or_default()).into())
}
IndexerSubCommand::BlobsForBlober {
blober,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_blober(
(*blober).into(),
Some(TimeRange {
start: start.to_owned(),
end: end.to_owned(),
}),
)
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::BlobsForPayer {
blob_payer,
network_name,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_payer(
blob_payer.to_owned(),
network_name.to_owned(),
Some(TimeRange {
start: start.to_owned(),
end: end.to_owned(),
}),
)
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::BlobsForNetwork {
network_name,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_network(
network_name.to_owned(),
Some(TimeRange {
start: start.to_owned(),
end: end.to_owned(),
}),
)
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
IndexerSubCommand::BlobsForNamespace {
namespace,
payer_pubkey,
time_args: TimeArgs { start, end },
} => {
let data = client
.get_blobs_by_namespace_for_payer(
namespace.to_owned(),
payer_pubkey.to_owned(),
Some(TimeRange {
start: start.to_owned(),
end: end.to_owned(),
}),
)
.await?;
Ok(IndexerCommandOutput::Blobs(data).into())
}
#[allow(deprecated)]
IndexerSubCommand::Proof(SlotArgs { slot }) => {
let proof = client.get_proof(*slot, identifier).await?;
Ok(IndexerCommandOutput::Proofs(Box::new(proof)).into())
}
#[allow(deprecated)]
IndexerSubCommand::ProofForBlob { blob } => {
let proof = client.get_proof_for_blob(blob.to_owned()).await?;
Ok(IndexerCommandOutput::Proofs(Box::new(proof)).into())
}
IndexerSubCommand::ListPayers { network_name } => {
let payers = client
.get_payers_by_network(network_name.to_owned())
.await?;
Ok(IndexerCommandOutput::Payers(payers.into_iter().map_into().collect()).into())
}
IndexerSubCommand::ZKProof { slot, proof_type } => {
let request_id = client
.checkpoint_custom_proof(*slot, identifier, *proof_type)
.await?;
Ok(IndexerCommandOutput::ZKProofs(request_id).into())
}
IndexerSubCommand::ProofRequestStatus { request_id } => {
let status = client
.get_proof_request_status(request_id.to_owned())
.await?;
Ok(IndexerCommandOutput::ProofRequestStatus(request_id.to_owned(), status).into())
}
}
}
}