use std::fmt::Display;
use nitro_da_blober::instruction::{
Close, DeclareBlob, DiscardBlob, FinalizeBlob, Initialize, InsertChunk,
};
use solana_rpc_client_api::client_error::Error;
use solana_sdk::{clock::Slot, commitment_config::ParseCommitmentLevelError};
use thiserror::Error;
use crate::{
tx::{Compound, CompoundDeclare, CompoundFinalize, MessageBuilder},
TransactionOutcome,
};
#[derive(Debug, Error)]
pub enum BloberClientError {
#[error(transparent)]
UploadBlob(#[from] UploadBlobError),
#[error(transparent)]
Indexer(#[from] IndexerError),
#[error(transparent)]
Deployment(#[from] DeploymentError),
#[error("Failed to query Solana RPC: {0}")]
SolanaRpc(#[from] Error),
#[error("Invalid commitment: {0}")]
InvalidCommitment(#[from] ParseCommitmentLevelError),
#[error("Invalid indexer url: {0}")]
InvalidIndexerUrl(#[from] jsonrpsee::core::client::Error),
#[error("Invalid key or namespace for blober")]
InvalidKeyOrNamespace,
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Ledger data blob error: {0}")]
LedgerDataBlob(#[from] LedgerDataBlobError),
}
#[derive(Debug, Error)]
pub enum LedgerDataBlobError {
#[error("No declare blob instruction found")]
DeclareNotFound,
#[error("Multiple declare instructions found")]
MultipleDeclares,
#[error("Declare blob size and inserts blob size mismatch")]
SizeMismatch,
#[error("No finalize instruction found")]
FinalizeNotFound,
#[error("Multiple finalize instructions found")]
MultipleFinalizes,
}
pub type BloberClientResult<T = ()> = Result<T, BloberClientError>;
#[derive(Error, Debug)]
pub enum OutcomeError {
#[error(
"Transaction outcomes were not successfull: \n{}",
.0.iter().filter_map(TransactionOutcome::error).map(|t| format!("- {}: {} [{}]", t.data, t.error, t.logs.join("\n"))).collect::<Vec<_>>().join("\n")
)]
Unsuccesful(Vec<TransactionOutcome<TransactionType>>),
}
#[derive(Error, Debug)]
pub enum UploadBlobError {
#[error("Failed to query Solana RPC: {0}")]
SolanaRpc(#[from] Error),
#[error(transparent)]
TransactionFailure(#[from] OutcomeError),
#[error("Fee Strategy conversion failure: {0}")]
ConversionError(&'static str),
#[error("Failed to declare blob: {0}")]
DeclareBlob(OutcomeError),
#[error("Failed to insert chunks: {0}")]
InsertChunks(OutcomeError),
#[error("Failed to finalize blob: {0}")]
FinalizeBlob(OutcomeError),
#[error("Failed to discard blob: {0}")]
DiscardBlob(OutcomeError),
#[error("Failed to compound upload: {0}")]
CompoundUpload(OutcomeError),
#[error("Failed to initialize blober: {0}")]
InitializeBlober(OutcomeError),
#[error("Failed to close blober: {0}")]
CloseBlober(OutcomeError),
}
#[derive(Error, Debug)]
pub enum IndexerError {
#[error("Failed to read blobs for slot {0} via indexer client: {1}")]
Blobs(Slot, String),
#[error("Failed to read proof for slot {0} via indexer client: {1}")]
Proof(Slot, String),
#[error("Failed to read blobs for blober {0} via indexer client: {1}")]
BlobsForBlober(String, String),
#[error("Failed to read proof for payer {0} via indexer client: {1}")]
BlobsForPayer(String, String),
#[error("Failed to read proof for blob {0} via indexer client: {1}")]
ProofForBlob(String, String),
}
#[derive(Error, Debug)]
pub enum DeploymentError {
#[error("Failed to create buffer account: {0}")]
Buffer(String),
#[error("Failed to deploy program: {0}")]
Deploy(String),
#[error("Failed to get minimum balance for rent exemption: {0}")]
RentBalance(String),
#[error("Failed to get recent blockhash")]
BlockHash,
#[error("Failed to read program bytecode: {0}")]
Bytecode(String),
}
#[derive(Debug, Clone, Copy)]
pub enum TransactionType {
CloseBlober,
Compound,
CompoundDeclare,
CompoundFinalize,
DeclareBlob,
DiscardBlob,
FinalizeBlob,
InitializeBlober,
InsertChunk(u16),
}
impl Display for TransactionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TransactionType::CloseBlober => write!(f, "CloseBlober"),
TransactionType::Compound => write!(f, "CompoundUpload"),
TransactionType::CompoundDeclare => write!(f, "CompoundDeclare"),
TransactionType::CompoundFinalize => write!(f, "CompoundFinalize"),
TransactionType::DeclareBlob => write!(f, "DeclareBlob"),
TransactionType::DiscardBlob => write!(f, "DiscardBlob"),
TransactionType::FinalizeBlob => write!(f, "FinalizeBlob"),
TransactionType::InitializeBlober => write!(f, "InitializeBlober"),
TransactionType::InsertChunk(i) => write!(f, "InsertChunk {i}"),
}
}
}
impl TransactionType {
pub(crate) fn num_signatures(&self) -> u16 {
match self {
TransactionType::CloseBlober => Close::NUM_SIGNATURES,
TransactionType::Compound => Compound::NUM_SIGNATURES,
TransactionType::CompoundDeclare => CompoundDeclare::NUM_SIGNATURES,
TransactionType::CompoundFinalize => CompoundFinalize::NUM_SIGNATURES,
TransactionType::DeclareBlob => DeclareBlob::NUM_SIGNATURES,
TransactionType::DiscardBlob => DiscardBlob::NUM_SIGNATURES,
TransactionType::FinalizeBlob => FinalizeBlob::NUM_SIGNATURES,
TransactionType::InitializeBlober => Initialize::NUM_SIGNATURES,
TransactionType::InsertChunk(_) => InsertChunk::NUM_SIGNATURES,
}
}
pub(crate) fn compute_unit_limit(&self) -> u32 {
match self {
TransactionType::CloseBlober => Close::COMPUTE_UNIT_LIMIT,
TransactionType::Compound => Compound::COMPUTE_UNIT_LIMIT,
TransactionType::CompoundDeclare => CompoundDeclare::COMPUTE_UNIT_LIMIT,
TransactionType::CompoundFinalize => CompoundFinalize::COMPUTE_UNIT_LIMIT,
TransactionType::DeclareBlob => DeclareBlob::COMPUTE_UNIT_LIMIT,
TransactionType::DiscardBlob => DiscardBlob::COMPUTE_UNIT_LIMIT,
TransactionType::FinalizeBlob => FinalizeBlob::COMPUTE_UNIT_LIMIT,
TransactionType::InitializeBlober => Initialize::COMPUTE_UNIT_LIMIT,
TransactionType::InsertChunk(_) => InsertChunk::COMPUTE_UNIT_LIMIT,
}
}
}