1use std::fmt::Display;
2
3use nitro_da_blober::instruction::{
4 Close, DeclareBlob, DiscardBlob, FinalizeBlob, Initialize, InsertChunk,
5};
6use solana_rpc_client_api::client_error::Error;
7use solana_sdk::{clock::Slot, commitment_config::ParseCommitmentLevelError};
8use thiserror::Error;
9
10use crate::{
11 TransactionOutcome,
12 tx::{Compound, CompoundDeclare, CompoundFinalize, MessageBuilder},
13};
14
15#[derive(Debug, Error)]
17pub enum BloberClientError {
18 #[error(transparent)]
20 UploadBlob(#[from] UploadBlobError),
21 #[error(transparent)]
23 Indexer(#[from] IndexerError),
24 #[error(transparent)]
26 Deployment(#[from] DeploymentError),
27 #[error("Failed to query Solana RPC: {0}")]
29 SolanaRpc(#[from] Error),
30 #[error("Invalid commitment: {0}")]
32 InvalidCommitment(#[from] ParseCommitmentLevelError),
33 #[error("Invalid indexer url: {0}")]
35 InvalidIndexerUrl(#[from] jsonrpsee::core::client::Error),
36 #[error("Invalid key or namespace for blober")]
38 InvalidKeyOrNamespace,
39 #[error(transparent)]
41 Io(#[from] std::io::Error),
42 #[error("Ledger data blob error: {0}")]
44 LedgerDataBlob(#[from] LedgerDataBlobError),
45}
46
47#[derive(Debug, Error)]
49pub enum LedgerDataBlobError {
50 #[error("No declare blob instruction found")]
52 DeclareNotFound,
53 #[error("Multiple declare instructions found")]
55 MultipleDeclares,
56 #[error("Declare blob size and inserts blob size mismatch")]
58 SizeMismatch,
59 #[error("No finalize instruction found")]
61 FinalizeNotFound,
62 #[error("Multiple finalize instructions found")]
64 MultipleFinalizes,
65}
66
67pub type BloberClientResult<T = ()> = Result<T, BloberClientError>;
69
70#[derive(Error, Debug)]
72pub enum OutcomeError {
73 #[error(
74 "Transaction outcomes were not successfull: \n{}",
75 .0.iter().filter_map(TransactionOutcome::error).map(|t| format!("- {}: {} [{}]", t.data, t.error, t.logs.join("\n"))).collect::<Vec<_>>().join("\n")
76 )]
77 Unsuccesful(Vec<TransactionOutcome<TransactionType>>),
78}
79
80#[derive(Error, Debug)]
82pub enum UploadBlobError {
83 #[error("Failed to query Solana RPC: {0}")]
85 SolanaRpc(#[from] Error),
86 #[error(transparent)]
88 TransactionFailure(#[from] OutcomeError),
89 #[error("Fee Strategy conversion failure: {0}")]
91 ConversionError(&'static str),
92 #[error("Failed to declare blob: {0}")]
94 DeclareBlob(OutcomeError),
95 #[error("Failed to insert chunks: {0}")]
97 InsertChunks(OutcomeError),
98 #[error("Failed to finalize blob: {0}")]
100 FinalizeBlob(OutcomeError),
101 #[error("Failed to discard blob: {0}")]
103 DiscardBlob(OutcomeError),
104 #[error("Failed to compound upload: {0}")]
106 CompoundUpload(OutcomeError),
107 #[error("Failed to initialize blober: {0}")]
109 InitializeBlober(OutcomeError),
110 #[error("Failed to close blober: {0}")]
112 CloseBlober(OutcomeError),
113}
114
115#[derive(Error, Debug)]
116pub enum IndexerError {
117 #[error("Failed to read blobs for slot {0} via indexer client: {1}")]
119 Blobs(Slot, String),
120 #[error("Failed to read proof for slot {0} via indexer client: {1}")]
122 Proof(Slot, String),
123}
124
125#[derive(Error, Debug)]
126pub enum DeploymentError {
127 #[error("Failed to create buffer account: {0}")]
129 Buffer(String),
130 #[error("Failed to deploy program: {0}")]
132 Deploy(String),
133 #[error("Failed to get minimum balance for rent exemption: {0}")]
135 RentBalance(String),
136 #[error("Failed to get recent blockhash")]
138 BlockHash,
139 #[error("Failed to read program bytecode: {0}")]
141 Bytecode(String),
142}
143
144#[derive(Debug, Clone, Copy)]
146pub enum TransactionType {
147 CloseBlober,
148 Compound,
149 CompoundDeclare,
150 CompoundFinalize,
151 DeclareBlob,
152 DiscardBlob,
153 FinalizeBlob,
154 InitializeBlober,
155 InsertChunk(u16),
156}
157
158impl Display for TransactionType {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 match self {
161 TransactionType::CloseBlober => write!(f, "CloseBlober"),
162 TransactionType::Compound => write!(f, "CompoundUpload"),
163 TransactionType::CompoundDeclare => write!(f, "CompoundDeclare"),
164 TransactionType::CompoundFinalize => write!(f, "CompoundFinalize"),
165 TransactionType::DeclareBlob => write!(f, "DeclareBlob"),
166 TransactionType::DiscardBlob => write!(f, "DiscardBlob"),
167 TransactionType::FinalizeBlob => write!(f, "FinalizeBlob"),
168 TransactionType::InitializeBlober => write!(f, "InitializeBlober"),
169 TransactionType::InsertChunk(i) => write!(f, "InsertChunk {i}"),
170 }
171 }
172}
173
174impl TransactionType {
175 pub(crate) fn num_signatures(&self) -> u16 {
177 match self {
178 TransactionType::CloseBlober => Close::NUM_SIGNATURES,
179 TransactionType::Compound => Compound::NUM_SIGNATURES,
180 TransactionType::CompoundDeclare => CompoundDeclare::NUM_SIGNATURES,
181 TransactionType::CompoundFinalize => CompoundFinalize::NUM_SIGNATURES,
182 TransactionType::DeclareBlob => DeclareBlob::NUM_SIGNATURES,
183 TransactionType::DiscardBlob => DiscardBlob::NUM_SIGNATURES,
184 TransactionType::FinalizeBlob => FinalizeBlob::NUM_SIGNATURES,
185 TransactionType::InitializeBlober => Initialize::NUM_SIGNATURES,
186 TransactionType::InsertChunk(_) => InsertChunk::NUM_SIGNATURES,
187 }
188 }
189
190 pub(crate) fn compute_unit_limit(&self) -> u32 {
192 match self {
193 TransactionType::CloseBlober => Close::COMPUTE_UNIT_LIMIT,
194 TransactionType::Compound => Compound::COMPUTE_UNIT_LIMIT,
195 TransactionType::CompoundDeclare => CompoundDeclare::COMPUTE_UNIT_LIMIT,
196 TransactionType::CompoundFinalize => CompoundFinalize::COMPUTE_UNIT_LIMIT,
197 TransactionType::DeclareBlob => DeclareBlob::COMPUTE_UNIT_LIMIT,
198 TransactionType::DiscardBlob => DiscardBlob::COMPUTE_UNIT_LIMIT,
199 TransactionType::FinalizeBlob => FinalizeBlob::COMPUTE_UNIT_LIMIT,
200 TransactionType::InitializeBlober => Initialize::COMPUTE_UNIT_LIMIT,
201 TransactionType::InsertChunk(_) => InsertChunk::COMPUTE_UNIT_LIMIT,
202 }
203 }
204}