1
2use {
3 async_trait::async_trait,
4 log::*,
5 serde::{Deserialize, Serialize},
6 solana_sdk::{
7 clock::{Slot, UnixTimestamp},
8 pubkey::Pubkey,
9 signature::Signature,
10 message::v0::LoadedAddresses,
11 deserialize_utils::default_on_eof,
12 transaction::{TransactionError, VersionedTransaction},
13 },
14 solana_transaction_status::{
15 ConfirmedBlock,
16 ConfirmedTransactionStatusWithSignature,
17 ConfirmedTransactionWithStatusMeta,
18 TransactionStatus,
19 TransactionStatusMeta,
20 TransactionWithStatusMeta,
21 VersionedTransactionWithStatusMeta,
22 TransactionByAddrInfo,
23 Reward,
24 },
25 std::{
26 boxed::Box,
27 },
28 thiserror::Error,
29 tokio::task::JoinError,
30};
31
32#[macro_use]
33extern crate serde_derive;
34
35pub mod compression;
36
37#[derive(Debug, Error)]
38pub enum Error {
39 #[error("Storage Error: {0}")]
40 StorageBackendError(Box<dyn std::error::Error + Send>),
41
42 #[error("I/O Error: {0}")]
43 IoError(std::io::Error),
44
45 #[error("Transaction encoded is not supported")]
46 UnsupportedTransactionEncoding,
47
48 #[error("Block not found: {0}")]
49 BlockNotFound(Slot),
50
51 #[error("Signature not found")]
52 SignatureNotFound,
53
54 #[error("tokio error")]
55 TokioJoinError(JoinError),
56
57 #[error("Cache Error: {0}")]
58 CacheError(String),
59}
60
61impl From<std::io::Error> for Error {
62 fn from(err: std::io::Error) -> Self {
63 Self::IoError(err)
64 }
65}
66
67pub type Result<T> = std::result::Result<T, Error>;
68
69
70#[derive(Serialize, Deserialize)]
79pub struct StoredConfirmedBlock {
80 previous_blockhash: String,
81 blockhash: String,
82 parent_slot: Slot,
83 transactions: Vec<StoredConfirmedBlockTransaction>,
84 rewards: StoredConfirmedBlockRewards,
85 block_time: Option<UnixTimestamp>,
87 #[serde(deserialize_with = "default_on_eof")]
88 block_height: Option<u64>,
89}
90
91#[derive(Serialize, Deserialize)]
92pub struct StoredConfirmedTransactionWithStatusMeta {
93 pub slot: Slot,
94 pub tx_with_meta: StoredConfirmedBlockTransaction,
95 pub block_time: Option<UnixTimestamp>,
96}
97
98impl From<ConfirmedTransactionWithStatusMeta> for StoredConfirmedTransactionWithStatusMeta {
99 fn from(value: ConfirmedTransactionWithStatusMeta) -> Self {
100 Self {
101 slot: value.slot,
102 tx_with_meta: value.tx_with_meta.into(),
103 block_time: value.block_time,
104 }
105 }
106}
107
108impl From<StoredConfirmedTransactionWithStatusMeta> for ConfirmedTransactionWithStatusMeta {
109 fn from(value: StoredConfirmedTransactionWithStatusMeta) -> Self {
110 Self {
111 slot: value.slot,
112 tx_with_meta: value.tx_with_meta.into(),
113 block_time: value.block_time,
114 }
115 }
116}
117
118impl From<ConfirmedBlock> for StoredConfirmedBlock {
119 fn from(confirmed_block: ConfirmedBlock) -> Self {
120 let ConfirmedBlock {
121 previous_blockhash,
122 blockhash,
123 parent_slot,
124 transactions,
125 rewards,
126 num_partitions: _num_partitions,
127 block_time,
128 block_height,
129 } = confirmed_block;
130
131 Self {
132 previous_blockhash,
133 blockhash,
134 parent_slot,
135 transactions: transactions.into_iter().map(|tx| tx.into()).collect(),
136 rewards: rewards.into_iter().map(|reward| reward.into()).collect(),
137 block_time,
138 block_height,
139 }
140 }
141}
142
143impl From<StoredConfirmedBlock> for ConfirmedBlock {
144 fn from(confirmed_block: StoredConfirmedBlock) -> Self {
145 let StoredConfirmedBlock {
146 previous_blockhash,
147 blockhash,
148 parent_slot,
149 transactions,
150 rewards,
151 block_time,
152 block_height,
153 } = confirmed_block;
154
155 Self {
156 previous_blockhash,
157 blockhash,
158 parent_slot,
159 transactions: transactions.into_iter().map(|tx| tx.into()).collect(),
160 rewards: rewards.into_iter().map(|reward| reward.into()).collect(),
161 num_partitions: None,
162 block_time,
163 block_height,
164 }
165 }
166}
167
168#[derive(Serialize, Deserialize)]
169pub struct StoredConfirmedBlockTransaction {
170 transaction: VersionedTransaction,
171 meta: Option<StoredConfirmedBlockTransactionStatusMeta>,
172}
173
174impl From<TransactionWithStatusMeta> for StoredConfirmedBlockTransaction {
175 fn from(value: TransactionWithStatusMeta) -> Self {
176 match value {
177 TransactionWithStatusMeta::MissingMetadata(transaction) => Self {
178 transaction: VersionedTransaction::from(transaction),
179 meta: None,
180 },
181 TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
182 transaction,
183 meta,
184 }) => Self {
185 transaction,
186 meta: Some(meta.into()),
187 },
188 }
189 }
190}
191
192impl From<StoredConfirmedBlockTransaction> for TransactionWithStatusMeta {
193 fn from(tx_with_meta: StoredConfirmedBlockTransaction) -> Self {
194 let StoredConfirmedBlockTransaction { transaction, meta } = tx_with_meta;
195 match meta {
196 None => Self::MissingMetadata(
197 transaction
198 .into_legacy_transaction()
199 .expect("versioned transactions always have meta"),
200 ),
201 Some(meta) => Self::Complete(VersionedTransactionWithStatusMeta {
202 transaction,
203 meta: meta.into(),
204 }),
205 }
206 }
207}
208
209#[derive(Serialize, Deserialize)]
210pub struct StoredConfirmedBlockTransactionStatusMeta {
211 err: Option<TransactionError>,
212 fee: u64,
213 pre_balances: Vec<u64>,
214 post_balances: Vec<u64>,
215}
216
217impl From<StoredConfirmedBlockTransactionStatusMeta> for TransactionStatusMeta {
218 fn from(value: StoredConfirmedBlockTransactionStatusMeta) -> Self {
219 let StoredConfirmedBlockTransactionStatusMeta {
220 err,
221 fee,
222 pre_balances,
223 post_balances,
224 } = value;
225 let status = match &err {
226 None => Ok(()),
227 Some(err) => Err(err.clone()),
228 };
229 Self {
230 status,
231 fee,
232 pre_balances,
233 post_balances,
234 inner_instructions: None,
235 log_messages: None,
236 pre_token_balances: None,
237 post_token_balances: None,
238 rewards: None,
239 loaded_addresses: LoadedAddresses::default(),
240 return_data: None,
241 compute_units_consumed: None,
242 }
243 }
244}
245
246impl From<TransactionStatusMeta> for StoredConfirmedBlockTransactionStatusMeta {
247 fn from(value: TransactionStatusMeta) -> Self {
248 let TransactionStatusMeta {
249 status,
250 fee,
251 pre_balances,
252 post_balances,
253 ..
254 } = value;
255 Self {
256 err: status.err(),
257 fee,
258 pre_balances,
259 post_balances,
260 }
261 }
262}
263
264pub type StoredConfirmedBlockRewards = Vec<StoredConfirmedBlockReward>;
265
266#[derive(Serialize, Deserialize)]
267pub struct StoredConfirmedBlockReward {
268 pubkey: String,
269 lamports: i64,
270}
271
272impl From<StoredConfirmedBlockReward> for Reward {
273 fn from(value: StoredConfirmedBlockReward) -> Self {
274 let StoredConfirmedBlockReward { pubkey, lamports } = value;
275 Self {
276 pubkey,
277 lamports,
278 post_balance: 0,
279 reward_type: None,
280 commission: None,
281 }
282 }
283}
284
285impl From<Reward> for StoredConfirmedBlockReward {
286 fn from(value: Reward) -> Self {
287 let Reward {
288 pubkey, lamports, ..
289 } = value;
290 Self { pubkey, lamports }
291 }
292}
293
294#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
295pub struct LegacyTransactionByAddrInfo {
296 pub signature: Signature, pub err: Option<TransactionError>, pub index: u32, pub memo: Option<String>, }
301
302impl From<LegacyTransactionByAddrInfo> for TransactionByAddrInfo {
303 fn from(legacy: LegacyTransactionByAddrInfo) -> Self {
304 let LegacyTransactionByAddrInfo {
305 signature,
306 err,
307 index,
308 memo,
309 } = legacy;
310
311 Self {
312 signature,
313 err,
314 index,
315 memo,
316 block_time: None,
317 }
318 }
319}
320
321#[async_trait]
322pub trait LedgerStorageAdapter: Send + Sync {
323 async fn get_first_available_block(&self) -> Result<Option<Slot>>;
324
325 async fn get_confirmed_blocks(&self, start_slot: Slot, limit: usize) -> Result<Vec<Slot>>;
326
327 async fn get_confirmed_block(&self, slot: Slot, use_cache: bool) -> Result<ConfirmedBlock>;
328
329 async fn get_signature_status(&self, signature: &Signature) -> Result<TransactionStatus>;
330
331 async fn get_full_transaction(
332 &self,
333 signature: &Signature,
334 ) -> Result<Option<ConfirmedTransactionWithStatusMeta>>;
335
336 async fn get_confirmed_transaction(
337 &self,
338 signature: &Signature,
339 ) -> Result<Option<ConfirmedTransactionWithStatusMeta>>;
340
341 async fn get_confirmed_signatures_for_address(
342 &self,
343 address: &Pubkey,
344 before_signature: Option<&Signature>,
345 until_signature: Option<&Signature>,
346 limit: usize,
347 ) -> Result<Vec<(ConfirmedTransactionStatusWithSignature, u32)>>;
348
349 async fn get_latest_stored_slot(&self) -> Result<Slot>;
350
351 fn clone_box(&self) -> Box<dyn LedgerStorageAdapter>;
352}