solana_binary_encoder/
transaction_status.rs

1
2use {
3    crate::{
4        // transaction::Transaction,
5        // instruction::CompiledInstruction,
6        // transaction::{Result as TransactionResult},
7        // versioned_transaction::{VersionedTransaction, TransactionVersion},
8        // versioned_message::VersionedMessage,
9        // message_v0::{Message as MessageV0, MessageAddressTableLookup},
10        // message::Message,
11        // loaded_message::LoadedMessage,
12        // account_decoder::{
13        //     UiTokenAmount
14        // },
15        // account_keys::AccountKeys,
16        // reward_type::RewardType,
17        option_serializer::OptionSerializer,
18        // message_header::MessageHeader,
19        parse_accounts::{ParsedAccount, parse_v0_message_accounts, parse_legacy_message_accounts},
20        // clock::{Slot, UnixTimestamp},
21        // transaction_error::TransactionError,
22        // loaded_addresses::LoadedAddresses,
23        parse_instruction::{parse, ParsedInstruction},
24        // transaction_context::TransactionReturnData,
25        // pubkey::{Pubkey, ParsePubkeyError},
26        // hash::{Hash, ParseHashError},
27        // signature::Signature,
28    },
29    solana_account_decoder::parse_token::UiTokenAmount,
30    solana_sdk::{
31        clock::{Slot, UnixTimestamp},
32        instruction::CompiledInstruction,
33        message::{
34            v0::{
35                self,
36                LoadedAddresses,
37                LoadedMessage,
38                MessageAddressTableLookup
39            },
40            AccountKeys,
41            Message,
42            MessageHeader,
43            VersionedMessage,
44        },
45        pubkey::{Pubkey, ParsePubkeyError},
46        signature::Signature,
47        transaction::{
48            Result as TransactionResult,
49            Transaction,
50            TransactionError,
51            TransactionVersion,
52            VersionedTransaction,
53        },
54        transaction_context::TransactionReturnData,
55        reward_type::RewardType,
56        signature::ParseSignatureError,
57        hash::{Hash, ParseHashError},
58    },
59    serde_derive::{Serialize,Deserialize},
60    thiserror::Error,
61};
62use std::{error::Error, fmt};
63use std::str::FromStr;
64// use crate::hash::ParseHashError;
65// use crate::signature::ParseSignatureError;
66
67#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
68pub struct TransactionByAddrInfo {
69    pub signature: Signature,          // The transaction signature
70    pub err: Option<TransactionError>, // None if the transaction executed successfully
71    pub index: u32,                    // Where the transaction is located in the block
72    pub memo: Option<String>,          // Transaction memo
73    pub block_time: Option<UnixTimestamp>,
74}
75
76#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub enum TransactionConfirmationStatus {
79    Processed,
80    Confirmed,
81    Finalized,
82}
83
84#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(rename_all = "camelCase")]
86pub struct TransactionStatus {
87    pub slot: Slot,
88    pub confirmations: Option<usize>,  // None = rooted
89    pub status: TransactionResult<()>, // legacy field
90    pub err: Option<TransactionError>,
91    pub confirmation_status: Option<TransactionConfirmationStatus>,
92}
93
94pub struct BlockEncodingOptions {
95    pub transaction_details: TransactionDetails,
96    pub show_rewards: bool,
97    pub max_supported_transaction_version: Option<u8>,
98}
99
100#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
101#[allow(clippy::large_enum_variant)]
102pub enum TransactionWithStatusMeta {
103    // Very old transactions may be missing metadata
104    MissingMetadata(Transaction),
105    // Versioned stored transaction always have metadata
106    Complete(VersionedTransactionWithStatusMeta),
107}
108
109
110
111#[derive(Error, Debug, PartialEq, Eq, Clone)]
112pub enum EncodeError {
113    #[error("Encoding does not support transaction version {0}")]
114    UnsupportedTransactionVersion(u8),
115}
116
117#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
118pub struct VersionedTransactionWithStatusMeta {
119    pub transaction: VersionedTransaction,
120    pub meta: TransactionStatusMeta,
121}
122
123
124
125/// Represents types that can be encoded into one of several encoding formats
126pub trait Encodable {
127    type Encoded;
128    fn encode(&self, encoding: UiTransactionEncoding) -> Self::Encoded;
129}
130
131/// Represents types that can be encoded into one of several encoding formats
132pub trait EncodableWithMeta {
133    type Encoded;
134    fn encode_with_meta(
135        &self,
136        encoding: UiTransactionEncoding,
137        meta: &TransactionStatusMeta,
138    ) -> Self::Encoded;
139    fn json_encode(&self) -> Self::Encoded;
140}
141
142impl EncodableWithMeta for VersionedTransaction {
143    type Encoded = EncodedTransaction;
144    fn encode_with_meta(
145        &self,
146        encoding: UiTransactionEncoding,
147        meta: &TransactionStatusMeta,
148    ) -> Self::Encoded {
149        match encoding {
150            UiTransactionEncoding::Binary => EncodedTransaction::LegacyBinary(
151                bs58::encode(bincode::serialize(self).unwrap()).into_string(),
152            ),
153            UiTransactionEncoding::Base58 => EncodedTransaction::Binary(
154                bs58::encode(bincode::serialize(self).unwrap()).into_string(),
155                TransactionBinaryEncoding::Base58,
156            ),
157            UiTransactionEncoding::Base64 => EncodedTransaction::Binary(
158                base64::encode(bincode::serialize(self).unwrap()),
159                TransactionBinaryEncoding::Base64,
160            ),
161            UiTransactionEncoding::Json => self.json_encode(),
162            UiTransactionEncoding::JsonParsed => EncodedTransaction::Json(UiTransaction {
163                signatures: self.signatures.iter().map(ToString::to_string).collect(),
164                message: match &self.message {
165                    VersionedMessage::Legacy(message) => {
166                        message.encode(UiTransactionEncoding::JsonParsed)
167                    }
168                    VersionedMessage::V0(message) => {
169                        message.encode_with_meta(UiTransactionEncoding::JsonParsed, meta)
170                    }
171                },
172            }),
173        }
174    }
175    fn json_encode(&self) -> Self::Encoded {
176        EncodedTransaction::Json(UiTransaction {
177            signatures: self.signatures.iter().map(ToString::to_string).collect(),
178            message: match &self.message {
179                VersionedMessage::Legacy(message) => message.encode(UiTransactionEncoding::Json),
180                VersionedMessage::V0(message) => message.json_encode(),
181            },
182        })
183    }
184}
185
186
187
188impl Encodable for Transaction {
189    type Encoded = EncodedTransaction;
190    fn encode(&self, encoding: UiTransactionEncoding) -> Self::Encoded {
191        match encoding {
192            UiTransactionEncoding::Binary => EncodedTransaction::LegacyBinary(
193                bs58::encode(bincode::serialize(self).unwrap()).into_string(),
194            ),
195            UiTransactionEncoding::Base58 => EncodedTransaction::Binary(
196                bs58::encode(bincode::serialize(self).unwrap()).into_string(),
197                TransactionBinaryEncoding::Base58,
198            ),
199            UiTransactionEncoding::Base64 => EncodedTransaction::Binary(
200                base64::encode(bincode::serialize(self).unwrap()),
201                TransactionBinaryEncoding::Base64,
202            ),
203            UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => {
204                EncodedTransaction::Json(UiTransaction {
205                    signatures: self.signatures.iter().map(ToString::to_string).collect(),
206                    message: self.message.encode(encoding),
207                })
208            }
209        }
210    }
211}
212
213impl Encodable for Message {
214    type Encoded = UiMessage;
215    fn encode(&self, encoding: UiTransactionEncoding) -> Self::Encoded {
216        if encoding == UiTransactionEncoding::JsonParsed {
217            let account_keys = AccountKeys::new(&self.account_keys, None);
218            UiMessage::Parsed(UiParsedMessage {
219                account_keys: parse_legacy_message_accounts(self),
220                recent_blockhash: self.recent_blockhash.to_string(),
221                instructions: self
222                    .instructions
223                    .iter()
224                    .map(|instruction| UiInstruction::parse(instruction, &account_keys, None))
225                    .collect(),
226                address_table_lookups: None,
227            })
228        } else {
229            UiMessage::Raw(UiRawMessage {
230                header: self.header,
231                account_keys: self.account_keys.iter().map(ToString::to_string).collect(),
232                recent_blockhash: self.recent_blockhash.to_string(),
233                instructions: self
234                    .instructions
235                    .iter()
236                    .map(|ix| UiCompiledInstruction::from(ix, None))
237                    .collect(),
238                address_table_lookups: None,
239            })
240        }
241    }
242}
243
244impl EncodableWithMeta for v0::Message {
245    type Encoded = UiMessage;
246    fn encode_with_meta(
247        &self,
248        encoding: UiTransactionEncoding,
249        meta: &TransactionStatusMeta,
250    ) -> Self::Encoded {
251        if encoding == UiTransactionEncoding::JsonParsed {
252            let account_keys = AccountKeys::new(&self.account_keys, Some(&meta.loaded_addresses));
253            let loaded_message = LoadedMessage::new_borrowed(self, &meta.loaded_addresses);
254            UiMessage::Parsed(UiParsedMessage {
255                account_keys: parse_v0_message_accounts(&loaded_message),
256                recent_blockhash: self.recent_blockhash.to_string(),
257                instructions: self
258                    .instructions
259                    .iter()
260                    .map(|instruction| UiInstruction::parse(instruction, &account_keys, None))
261                    .collect(),
262                address_table_lookups: Some(
263                    self.address_table_lookups.iter().map(Into::into).collect(),
264                ),
265            })
266        } else {
267            self.json_encode()
268        }
269    }
270    fn json_encode(&self) -> Self::Encoded {
271        UiMessage::Raw(UiRawMessage {
272            header: self.header,
273            account_keys: self.account_keys.iter().map(ToString::to_string).collect(),
274            recent_blockhash: self.recent_blockhash.to_string(),
275            instructions: self
276                .instructions
277                .iter()
278                .map(|ix| UiCompiledInstruction::from(ix, None))
279                .collect(),
280            address_table_lookups: Some(
281                self.address_table_lookups.iter().map(Into::into).collect(),
282            ),
283        })
284    }
285}
286
287impl DecodableWithMeta for v0::Message {
288    type Encoded = UiMessage;
289    type Decoded = v0::Message;
290
291    fn decode_with_meta(
292        encoded: Self::Encoded,
293        decoding: UiTransactionEncoding,
294        version: Option<TransactionVersion>
295        // _meta: &TransactionStatusMeta,
296    ) -> Result<Self::Decoded, DecodeError> {
297        match decoding {
298            UiTransactionEncoding::Json => match encoded {
299                UiMessage::Raw(_) => Self::json_decode(encoded, version),
300                UiMessage::Parsed(_) => Err(DecodeError::UnsupportedEncoding),
301            },
302            _ => Err(DecodeError::UnsupportedEncoding),
303        }
304    }
305
306    fn json_decode(encoded: Self::Encoded, version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError> {
307    // fn decode(encoded: Self::Encoded) -> Result<Self::Decoded, DecodeError> {
308        if let UiMessage::Raw(raw_msg) = encoded {
309            let header = raw_msg.header;
310            let account_keys = raw_msg.account_keys
311                .iter()
312                .map(|s| s.parse::<Pubkey>())
313                .collect::<Result<Vec<_>, _>>()
314                .map_err(|_| DecodeError::InvalidAccountKey)?;
315            let recent_blockhash = raw_msg.recent_blockhash.parse::<Hash>()
316                .map_err(|_| DecodeError::InvalidBlockhash)?;
317            // let instructions = raw_msg.instructions
318            //     .iter()
319            //     .map(|i| decode_ui_instruction(i))
320            //     .collect::<Result<Vec<_>, _>>()?;
321            // let address_table_lookups = match raw_msg.address_table_lookups {
322            //     Some(lookups) => lookups
323            //         .iter()
324            //         .map(|lookup| decode_ui_address_table_lookup(lookup))
325            //         .collect::<Result<Vec<_>, _>>()?,
326            //     None => vec![],
327            // };
328            let instructions = raw_msg.instructions
329                .iter()
330                .map(|i| CompiledInstruction::from(i.clone()))
331                .collect::<Vec<_>>();
332            let address_table_lookups = match raw_msg.address_table_lookups {
333                Some(lookups) => lookups
334                    .iter()
335                    .map(|lookup| MessageAddressTableLookup::try_from(lookup))
336                    .collect::<Result<Vec<_>, _>>()?,
337                None => vec![],
338            };
339
340            Ok(Self {
341                header,
342                account_keys,
343                recent_blockhash,
344                instructions,
345                address_table_lookups,
346            })
347        } else {
348            Err(DecodeError::UnsupportedEncoding)
349        }
350    }
351}
352
353
354trait JsonAccounts {
355    type Encoded;
356    fn build_json_accounts(&self) -> Self::Encoded;
357}
358
359impl JsonAccounts for Transaction {
360    type Encoded = EncodedTransaction;
361    fn build_json_accounts(&self) -> Self::Encoded {
362        EncodedTransaction::Accounts(UiAccountsList {
363            signatures: self.signatures.iter().map(ToString::to_string).collect(),
364            account_keys: parse_legacy_message_accounts(&self.message),
365        })
366    }
367}
368
369#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
370pub struct TransactionStatusMeta {
371    pub status: TransactionResult<()>,
372    pub fee: u64,
373    pub pre_balances: Vec<u64>,
374    pub post_balances: Vec<u64>,
375    pub inner_instructions: Option<Vec<InnerInstructions>>,
376    pub log_messages: Option<Vec<String>>,
377    pub pre_token_balances: Option<Vec<TransactionTokenBalance>>,
378    pub post_token_balances: Option<Vec<TransactionTokenBalance>>,
379    pub rewards: Option<Rewards>,
380    pub loaded_addresses: LoadedAddresses,
381    pub return_data: Option<TransactionReturnData>,
382    pub compute_units_consumed: Option<u64>,
383}
384
385#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
386pub struct InnerInstructions {
387    /// Transaction instruction index
388    pub index: u8,
389    /// List of inner instructions
390    pub instructions: Vec<InnerInstruction>,
391    // pub instructions: Vec<CompiledInstruction>,
392}
393
394#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
395pub struct InnerInstruction {
396    /// Compiled instruction
397    pub instruction: CompiledInstruction,
398    /// Invocation stack height of the instruction,
399    pub stack_height: Option<u32>,
400}
401
402#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
403#[serde(rename_all = "camelCase")]
404pub struct UiInnerInstructions {
405    /// Transaction instruction index
406    pub index: u8,
407    /// List of inner instructions
408    pub instructions: Vec<UiInstruction>,
409}
410
411impl UiInnerInstructions {
412    fn parse(inner_instructions: InnerInstructions, account_keys: &AccountKeys) -> Self {
413        Self {
414            index: inner_instructions.index,
415            instructions: inner_instructions
416                .instructions
417                .iter()
418                .map(
419                    |InnerInstruction {
420                         instruction: ix,
421                         stack_height,
422                     }| {
423                        UiInstruction::parse(ix, account_keys, *stack_height)
424                    },
425                )
426                .collect(),
427        }
428    }
429}
430
431impl From<InnerInstructions> for UiInnerInstructions {
432    fn from(inner_instructions: InnerInstructions) -> Self {
433        Self {
434            index: inner_instructions.index,
435            instructions: inner_instructions
436                .instructions
437                .iter()
438                .map(
439                    |InnerInstruction {
440                         instruction: ix,
441                         stack_height,
442                     }| {
443                        UiInstruction::Compiled(UiCompiledInstruction::from(ix, *stack_height))
444                    },
445                )
446                .collect(),
447        }
448    }
449}
450
451/// A duplicate representation of an Instruction for pretty JSON serialization
452#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
453#[serde(rename_all = "camelCase", untagged)]
454pub enum UiInstruction {
455    Compiled(UiCompiledInstruction),
456    Parsed(UiParsedInstruction),
457}
458
459impl UiInstruction {
460    fn parse(
461        instruction: &CompiledInstruction,
462        account_keys: &AccountKeys,
463        stack_height: Option<u32>,
464    ) -> Self {
465        let program_id = &account_keys[instruction.program_id_index as usize];
466        if let Ok(parsed_instruction) = parse(program_id, instruction, account_keys, stack_height) {
467            UiInstruction::Parsed(UiParsedInstruction::Parsed(parsed_instruction))
468        } else {
469            UiInstruction::Parsed(UiParsedInstruction::PartiallyDecoded(
470                UiPartiallyDecodedInstruction::from(instruction, account_keys, stack_height),
471            ))
472        }
473    }
474}
475
476#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
477#[serde(rename_all = "camelCase", untagged)]
478pub enum UiParsedInstruction {
479    Parsed(ParsedInstruction),
480    PartiallyDecoded(UiPartiallyDecodedInstruction),
481}
482
483// #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
484// #[serde(rename_all = "camelCase")]
485// pub struct ParsedInstruction {
486//     pub program: String,
487//     pub program_id: String,
488//     pub parsed: Value,
489// }
490
491/// A partially decoded CompiledInstruction that includes explicit account addresses
492#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
493#[serde(rename_all = "camelCase")]
494pub struct UiPartiallyDecodedInstruction {
495    pub program_id: String,
496    pub accounts: Vec<String>,
497    pub data: String,
498    pub stack_height: Option<u32>,
499}
500
501impl UiPartiallyDecodedInstruction {
502    fn from(
503        instruction: &CompiledInstruction,
504        account_keys: &AccountKeys,
505        stack_height: Option<u32>,
506    ) -> Self {
507        Self {
508            program_id: account_keys[instruction.program_id_index as usize].to_string(),
509            accounts: instruction
510                .accounts
511                .iter()
512                .map(|&i| account_keys[i as usize].to_string())
513                .collect(),
514            data: bs58::encode(instruction.data.clone()).into_string(),
515            stack_height,
516        }
517    }
518}
519
520/// A duplicate representation of a CompiledInstruction for pretty JSON serialization
521#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
522#[serde(rename_all = "camelCase")]
523pub struct UiCompiledInstruction {
524    pub program_id_index: u8,
525    pub accounts: Vec<u8>,
526    pub data: String,
527    pub stack_height: Option<u32>,
528}
529
530impl UiCompiledInstruction {
531    fn from(instruction: &CompiledInstruction, stack_height: Option<u32>) -> Self {
532        Self {
533            program_id_index: instruction.program_id_index,
534            accounts: instruction.accounts.clone(),
535            data: bs58::encode(&instruction.data).into_string(),
536            stack_height,
537        }
538    }
539}
540
541// impl From<&CompiledInstruction> for UiCompiledInstruction {
542//     fn from(instruction: &CompiledInstruction) -> Self {
543//         Self {
544//             program_id_index: instruction.program_id_index,
545//             accounts: instruction.accounts.clone(),
546//             data: bs58::encode(instruction.data.clone()).into_string(),
547//         }
548//     }
549// }
550
551#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
552pub struct TransactionTokenBalance {
553    pub account_index: u8,
554    pub mint: String,
555    pub ui_token_amount: UiTokenAmount,
556    pub owner: String,
557    pub program_id: String,
558}
559
560#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
561pub struct ConfirmedTransactionWithStatusMeta {
562    pub slot: Slot,
563    pub tx_with_meta: TransactionWithStatusMeta,
564    pub block_time: Option<UnixTimestamp>,
565}
566
567// Not used for now.
568#[allow(dead_code)]
569impl ConfirmedTransactionWithStatusMeta {
570    pub fn encode(
571        self,
572        encoding: UiTransactionEncoding,
573        max_supported_transaction_version: Option<u8>,
574    ) -> Result<EncodedConfirmedTransactionWithStatusMeta, EncodeError> {
575        Ok(EncodedConfirmedTransactionWithStatusMeta {
576            slot: self.slot,
577            transaction: self.tx_with_meta.encode(
578                encoding,
579                max_supported_transaction_version,
580                true,
581            )?,
582            block_time: self.block_time,
583        })
584    }
585}
586
587#[derive(Debug, PartialEq, Serialize, Deserialize)]
588#[serde(rename_all = "camelCase")]
589pub struct EncodedConfirmedTransactionWithStatusMeta {
590    pub slot: Slot,
591    #[serde(flatten)]
592    pub transaction: EncodedTransactionWithStatusMeta,
593    pub block_time: Option<UnixTimestamp>,
594}
595
596#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
597#[serde(rename_all = "camelCase")]
598pub struct EncodedTransactionWithStatusMeta {
599    pub transaction: EncodedTransaction,
600    pub meta: Option<UiTransactionStatusMeta>,
601    #[serde(default, skip_serializing_if = "Option::is_none")]
602    pub version: Option<TransactionVersion>,
603}
604
605#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
606#[serde(rename_all = "camelCase", untagged)]
607pub enum EncodedTransaction {
608    LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility
609    Binary(String, TransactionBinaryEncoding),
610    Json(UiTransaction),
611    Accounts(UiAccountsList),
612}
613
614impl EncodedTransaction {
615    pub fn decode(&self) -> Option<VersionedTransaction> {
616        let (blob, encoding) = match self {
617            Self::Json(_) | Self::Accounts(_) => return None,
618            Self::LegacyBinary(blob) => (blob, TransactionBinaryEncoding::Base58),
619            Self::Binary(blob, encoding) => (blob, *encoding),
620        };
621
622        let transaction: Option<VersionedTransaction> = match encoding {
623            TransactionBinaryEncoding::Base58 => bs58::decode(blob)
624                .into_vec()
625                .ok()
626                .and_then(|bytes| bincode::deserialize(&bytes).ok()),
627            TransactionBinaryEncoding::Base64 => base64::decode(blob)
628                .ok()
629                .and_then(|bytes| bincode::deserialize(&bytes).ok()),
630        };
631
632        transaction.filter(|transaction| {
633            transaction
634                .sanitize(
635                    true, // require_static_program_ids
636                )
637                .is_ok()
638        })
639    }
640}
641
642/// A duplicate representation of TransactionStatusMeta with `err` field
643#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
644#[serde(rename_all = "camelCase")]
645pub struct UiTransactionStatusMeta {
646    pub err: Option<TransactionError>,
647    pub status: TransactionResult<()>, // This field is deprecated.  See https://github.com/solana-labs/solana/issues/9302
648    pub fee: u64,
649    pub pre_balances: Vec<u64>,
650    pub post_balances: Vec<u64>,
651    #[serde(
652        default = "OptionSerializer::none",
653        skip_serializing_if = "OptionSerializer::should_skip"
654    )]
655    pub inner_instructions: OptionSerializer<Vec<UiInnerInstructions>>,
656    #[serde(
657        default = "OptionSerializer::none",
658        skip_serializing_if = "OptionSerializer::should_skip"
659    )]
660    pub log_messages: OptionSerializer<Vec<String>>,
661    #[serde(
662        default = "OptionSerializer::none",
663        skip_serializing_if = "OptionSerializer::should_skip"
664    )]
665    pub pre_token_balances: OptionSerializer<Vec<UiTransactionTokenBalance>>,
666    #[serde(
667        default = "OptionSerializer::none",
668        skip_serializing_if = "OptionSerializer::should_skip"
669    )]
670    pub post_token_balances: OptionSerializer<Vec<UiTransactionTokenBalance>>,
671    #[serde(
672        default = "OptionSerializer::none",
673        skip_serializing_if = "OptionSerializer::should_skip"
674    )]
675    pub rewards: OptionSerializer<Rewards>,
676    #[serde(
677        default = "OptionSerializer::skip",
678        skip_serializing_if = "OptionSerializer::should_skip"
679    )]
680    pub loaded_addresses: OptionSerializer<UiLoadedAddresses>,
681    #[serde(
682        default = "OptionSerializer::skip",
683        skip_serializing_if = "OptionSerializer::should_skip"
684    )]
685    pub return_data: OptionSerializer<UiTransactionReturnData>,
686    #[serde(
687        default = "OptionSerializer::skip",
688        skip_serializing_if = "OptionSerializer::should_skip"
689    )]
690    pub compute_units_consumed: OptionSerializer<u64>,
691}
692
693impl UiTransactionStatusMeta {
694    fn parse(meta: TransactionStatusMeta, static_keys: &[Pubkey], show_rewards: bool) -> Self {
695        let account_keys = AccountKeys::new(static_keys, Some(&meta.loaded_addresses));
696        Self {
697            err: meta.status.clone().err(),
698            status: meta.status,
699            fee: meta.fee,
700            pre_balances: meta.pre_balances,
701            post_balances: meta.post_balances,
702            inner_instructions: meta
703                .inner_instructions
704                .map(|ixs| {
705                    ixs.into_iter()
706                        .map(|ix| UiInnerInstructions::parse(ix, &account_keys))
707                        .collect()
708                })
709                .into(),
710            log_messages: meta.log_messages.into(),
711            pre_token_balances: meta
712                .pre_token_balances
713                .map(|balance| balance.into_iter().map(Into::into).collect())
714                .into(),
715            post_token_balances: meta
716                .post_token_balances
717                .map(|balance| balance.into_iter().map(Into::into).collect())
718                .into(),
719            rewards: if show_rewards { meta.rewards } else { None }.into(),
720            loaded_addresses: OptionSerializer::Skip,
721            return_data: OptionSerializer::or_skip(
722                meta.return_data.map(|return_data| return_data.into()),
723            ),
724            compute_units_consumed: OptionSerializer::or_skip(meta.compute_units_consumed),
725        }
726    }
727
728    fn build_simple(meta: TransactionStatusMeta, show_rewards: bool) -> Self {
729        Self {
730            err: meta.status.clone().err(),
731            status: meta.status,
732            fee: meta.fee,
733            pre_balances: meta.pre_balances,
734            post_balances: meta.post_balances,
735            inner_instructions: OptionSerializer::Skip,
736            log_messages: OptionSerializer::Skip,
737            pre_token_balances: meta
738                .pre_token_balances
739                .map(|balance| balance.into_iter().map(Into::into).collect())
740                .into(),
741            post_token_balances: meta
742                .post_token_balances
743                .map(|balance| balance.into_iter().map(Into::into).collect())
744                .into(),
745            rewards: if show_rewards {
746                meta.rewards.into()
747            } else {
748                OptionSerializer::Skip
749            },
750            loaded_addresses: OptionSerializer::Skip,
751            return_data: OptionSerializer::Skip,
752            compute_units_consumed: OptionSerializer::Skip,
753        }
754    }
755}
756
757impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
758    fn from(meta: TransactionStatusMeta) -> Self {
759        Self {
760            err: meta.status.clone().err(),
761            status: meta.status,
762            fee: meta.fee,
763            pre_balances: meta.pre_balances,
764            post_balances: meta.post_balances,
765            inner_instructions: meta
766                .inner_instructions
767                .map(|ixs| ixs.into_iter().map(Into::into).collect())
768                .into(),
769            log_messages: meta.log_messages.into(),
770            pre_token_balances: meta
771                .pre_token_balances
772                .map(|balance| balance.into_iter().map(Into::into).collect())
773                .into(),
774            post_token_balances: meta
775                .post_token_balances
776                .map(|balance| balance.into_iter().map(Into::into).collect())
777                .into(),
778            rewards: meta.rewards.into(),
779            loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)).into(),
780            return_data: OptionSerializer::or_skip(
781                meta.return_data.map(|return_data| return_data.into()),
782            ),
783            compute_units_consumed: OptionSerializer::or_skip(meta.compute_units_consumed),
784        }
785    }
786}
787
788#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
789#[serde(rename_all = "camelCase")]
790pub struct Reward {
791    pub pubkey: String,
792    pub lamports: i64,
793    pub post_balance: u64, // Account balance in lamports after `lamports` was applied
794    pub reward_type: Option<RewardType>,
795    pub commission: Option<u8>, // Vote account commission when the reward was credited, only present for voting and staking rewards
796}
797
798pub type Rewards = Vec<Reward>;
799
800/// A duplicate representation of LoadedAddresses
801#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
802#[serde(rename_all = "camelCase")]
803pub struct UiLoadedAddresses {
804    pub writable: Vec<String>,
805    pub readonly: Vec<String>,
806}
807
808impl From<&LoadedAddresses> for UiLoadedAddresses {
809    fn from(loaded_addresses: &LoadedAddresses) -> Self {
810        Self {
811            writable: loaded_addresses
812                .writable
813                .iter()
814                .map(ToString::to_string)
815                .collect(),
816            readonly: loaded_addresses
817                .readonly
818                .iter()
819                .map(ToString::to_string)
820                .collect(),
821        }
822    }
823}
824
825#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
826#[serde(rename_all = "camelCase")]
827pub struct UiTransactionReturnData {
828    pub program_id: String,
829    pub data: (String, UiReturnDataEncoding),
830}
831
832impl Default for UiTransactionReturnData {
833    fn default() -> Self {
834        Self {
835            program_id: String::default(),
836            data: (String::default(), UiReturnDataEncoding::Base64),
837        }
838    }
839}
840
841impl From<TransactionReturnData> for UiTransactionReturnData {
842    fn from(return_data: TransactionReturnData) -> Self {
843        Self {
844            program_id: return_data.program_id.to_string(),
845            data: (
846                base64::encode(return_data.data),
847                UiReturnDataEncoding::Base64,
848            ),
849        }
850    }
851}
852
853#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
854#[serde(rename_all = "camelCase")]
855pub enum UiReturnDataEncoding {
856    Base64,
857}
858
859#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
860#[serde(rename_all = "camelCase")]
861pub enum TransactionBinaryEncoding {
862    Base58,
863    Base64,
864}
865
866#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
867#[serde(rename_all = "camelCase")]
868pub struct UiTransactionTokenBalance {
869    pub account_index: u8,
870    pub mint: String,
871    pub ui_token_amount: UiTokenAmount,
872    #[serde(
873        default = "OptionSerializer::skip",
874        skip_serializing_if = "OptionSerializer::should_skip"
875    )]
876    pub owner: OptionSerializer<String>,
877    #[serde(
878        default = "OptionSerializer::skip",
879        skip_serializing_if = "OptionSerializer::should_skip"
880    )]
881    pub program_id: OptionSerializer<String>,
882}
883
884impl From<TransactionTokenBalance> for UiTransactionTokenBalance {
885    fn from(token_balance: TransactionTokenBalance) -> Self {
886        Self {
887            account_index: token_balance.account_index,
888            mint: token_balance.mint,
889            ui_token_amount: token_balance.ui_token_amount,
890            owner: if !token_balance.owner.is_empty() {
891                OptionSerializer::Some(token_balance.owner)
892            } else {
893                OptionSerializer::Skip
894            },
895            program_id: if !token_balance.program_id.is_empty() {
896                OptionSerializer::Some(token_balance.program_id)
897            } else {
898                OptionSerializer::Skip
899            },
900        }
901    }
902}
903
904/// A duplicate representation of a Transaction for pretty JSON serialization
905#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
906#[serde(rename_all = "camelCase")]
907pub struct UiTransaction {
908    pub signatures: Vec<String>,
909    pub message: UiMessage,
910}
911
912#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
913#[serde(rename_all = "camelCase", untagged)]
914pub enum UiMessage {
915    Parsed(UiParsedMessage),
916    Raw(UiRawMessage),
917}
918
919/// A duplicate representation of a Message, in raw format, for pretty JSON serialization
920#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
921#[serde(rename_all = "camelCase")]
922pub struct UiRawMessage {
923    pub header: MessageHeader,
924    pub account_keys: Vec<String>,
925    pub recent_blockhash: String,
926    pub instructions: Vec<UiCompiledInstruction>,
927    #[serde(default, skip_serializing_if = "Option::is_none")]
928    pub address_table_lookups: Option<Vec<UiAddressTableLookup>>,
929}
930
931#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
932#[serde(rename_all = "camelCase")]
933pub struct UiAccountsList {
934    pub signatures: Vec<String>,
935    pub account_keys: Vec<ParsedAccount>,
936}
937
938/// A duplicate representation of a MessageAddressTableLookup, in raw format, for pretty JSON serialization
939#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
940#[serde(rename_all = "camelCase")]
941pub struct UiAddressTableLookup {
942    pub account_key: String,
943    pub writable_indexes: Vec<u8>,
944    pub readonly_indexes: Vec<u8>,
945}
946
947impl From<&MessageAddressTableLookup> for UiAddressTableLookup {
948    fn from(lookup: &MessageAddressTableLookup) -> Self {
949        Self {
950            account_key: lookup.account_key.to_string(),
951            writable_indexes: lookup.writable_indexes.clone(),
952            readonly_indexes: lookup.readonly_indexes.clone(),
953        }
954    }
955}
956
957impl TryFrom<&UiAddressTableLookup> for MessageAddressTableLookup {
958    type Error = DecodeError;
959
960    fn try_from(lookup: &UiAddressTableLookup) -> Result<Self, Self::Error> {
961        let account_key = Pubkey::from_str(&lookup.account_key)
962            .map_err(|_| DecodeError::ParsePubkeyFailed(ParsePubkeyError::Invalid))?;
963        Ok(Self {
964            account_key,
965            writable_indexes: lookup.writable_indexes.clone(),
966            readonly_indexes: lookup.readonly_indexes.clone(),
967        })
968    }
969}
970
971/// A duplicate representation of a Message, in parsed format, for pretty JSON serialization
972#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
973#[serde(rename_all = "camelCase")]
974pub struct UiParsedMessage {
975    pub account_keys: Vec<ParsedAccount>,
976    pub recent_blockhash: String,
977    pub instructions: Vec<UiInstruction>,
978    pub address_table_lookups: Option<Vec<UiAddressTableLookup>>,
979}
980
981#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
982#[serde(rename_all = "camelCase")]
983pub enum UiTransactionEncoding {
984    Binary, // Legacy. Retained for RPC backwards compatibility
985    Base64,
986    Base58,
987    Json,
988    JsonParsed,
989}
990
991#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
992#[serde(rename_all = "camelCase")]
993pub enum TransactionDetails {
994    Full,
995    Signatures,
996    None,
997    Accounts,
998}
999
1000impl Default for TransactionDetails {
1001    fn default() -> Self {
1002        Self::Full
1003    }
1004}
1005
1006#[derive(Debug, Error)]
1007pub enum ConvertBlockError {
1008    #[error("transactions missing after converted, before: {0}, after: {1}")]
1009    TransactionsMissing(usize, usize),
1010}
1011
1012#[derive(Clone, Debug, PartialEq)]
1013pub struct ConfirmedBlock {
1014    pub previous_blockhash: String,
1015    pub blockhash: String,
1016    pub parent_slot: Slot,
1017    pub transactions: Vec<TransactionWithStatusMeta>,
1018    pub rewards: Rewards,
1019    pub block_time: Option<UnixTimestamp>,
1020    pub block_height: Option<u64>,
1021}
1022
1023// Confirmed block with type guarantees that transaction metadata
1024// is always present. Used for uploading to HBase.
1025#[derive(Clone, Debug, PartialEq)]
1026pub struct VersionedConfirmedBlock {
1027    pub previous_blockhash: String,
1028    pub blockhash: String,
1029    pub parent_slot: Slot,
1030    pub transactions: Vec<VersionedTransactionWithStatusMeta>,
1031    pub rewards: Rewards,
1032    pub block_time: Option<UnixTimestamp>,
1033    pub block_height: Option<u64>,
1034}
1035
1036impl From<VersionedConfirmedBlock> for ConfirmedBlock {
1037    fn from(block: VersionedConfirmedBlock) -> Self {
1038        Self {
1039            previous_blockhash: block.previous_blockhash,
1040            blockhash: block.blockhash,
1041            parent_slot: block.parent_slot,
1042            transactions: block
1043                .transactions
1044                .into_iter()
1045                .map(TransactionWithStatusMeta::Complete)
1046                .collect(),
1047            rewards: block.rewards,
1048            block_time: block.block_time,
1049            block_height: block.block_height,
1050        }
1051    }
1052}
1053
1054
1055
1056#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
1057#[serde(rename_all = "camelCase")]
1058pub struct UiConfirmedBlock {
1059    pub previous_blockhash: String,
1060    pub blockhash: String,
1061    pub parent_slot: Slot,
1062    #[serde(default, skip_serializing_if = "Option::is_none")]
1063    pub transactions: Option<Vec<EncodedTransactionWithStatusMeta>>,
1064    #[serde(default, skip_serializing_if = "Option::is_none")]
1065    pub signatures: Option<Vec<String>>,
1066    #[serde(default, skip_serializing_if = "Option::is_none")]
1067    pub rewards: Option<Rewards>,
1068    pub block_time: Option<UnixTimestamp>,
1069    pub block_height: Option<u64>,
1070}
1071
1072#[derive(Debug, PartialEq, Serialize, Deserialize)]
1073#[serde(rename_all = "camelCase")]
1074pub struct EncodedConfirmedBlock {
1075    pub previous_blockhash: String,
1076    pub blockhash: String,
1077    pub parent_slot: Slot,
1078    pub transactions: Vec<EncodedTransactionWithStatusMeta>,
1079    pub rewards: Rewards,
1080    pub block_time: Option<UnixTimestamp>,
1081    pub block_height: Option<u64>,
1082}
1083
1084impl From<UiConfirmedBlock> for EncodedConfirmedBlock {
1085    fn from(block: UiConfirmedBlock) -> Self {
1086        Self {
1087            previous_blockhash: block.previous_blockhash,
1088            blockhash: block.blockhash,
1089            parent_slot: block.parent_slot,
1090            transactions: block.transactions.unwrap_or_default(),
1091            rewards: block.rewards.unwrap_or_default(),
1092            block_time: block.block_time,
1093            block_height: block.block_height,
1094        }
1095    }
1096}
1097
1098
1099
1100impl VersionedTransactionWithStatusMeta {
1101    fn validate_version(
1102        &self,
1103        max_supported_transaction_version: Option<u8>,
1104    ) -> Result<Option<TransactionVersion>, EncodeError> {
1105        match (
1106            max_supported_transaction_version,
1107            self.transaction.version(),
1108        ) {
1109            // Set to none because old clients can't handle this field
1110            (None, TransactionVersion::LEGACY) => Ok(None),
1111            (None, TransactionVersion::Number(version)) => {
1112                Err(EncodeError::UnsupportedTransactionVersion(version))
1113            }
1114            (Some(_), TransactionVersion::LEGACY) => Ok(Some(TransactionVersion::LEGACY)),
1115            (Some(max_version), TransactionVersion::Number(version)) => {
1116                if version <= max_version {
1117                    Ok(Some(TransactionVersion::Number(version)))
1118                } else {
1119                    Err(EncodeError::UnsupportedTransactionVersion(version))
1120                }
1121            }
1122        }
1123    }
1124
1125    pub fn account_keys(&self) -> AccountKeys {
1126        AccountKeys::new(
1127            self.transaction.message.static_account_keys(),
1128            Some(&self.meta.loaded_addresses),
1129        )
1130    }
1131
1132    pub fn encode(
1133        self,
1134        encoding: UiTransactionEncoding,
1135        max_supported_transaction_version: Option<u8>,
1136        show_rewards: bool,
1137    ) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
1138        let version = self.validate_version(max_supported_transaction_version)?;
1139
1140        Ok(EncodedTransactionWithStatusMeta {
1141            transaction: self.transaction.encode_with_meta(encoding, &self.meta),
1142            meta: Some(match encoding {
1143                UiTransactionEncoding::JsonParsed => UiTransactionStatusMeta::parse(
1144                    self.meta,
1145                    self.transaction.message.static_account_keys(),
1146                    show_rewards,
1147                ),
1148                _ => {
1149                    let mut meta = UiTransactionStatusMeta::from(self.meta);
1150                    if !show_rewards {
1151                        meta.rewards = OptionSerializer::None;
1152                    }
1153                    meta
1154                }
1155            }),
1156            version,
1157        })
1158    }
1159
1160    pub fn decode(
1161        encoded: EncodedTransactionWithStatusMeta,
1162        encoding: UiTransactionEncoding,
1163        // meta: Option<&UiTransactionStatusMeta>,
1164    ) -> Result<Self, DecodeError> {
1165        // Decoding the transaction
1166        let transaction = match VersionedTransaction::decode_with_meta(encoded.transaction, encoding, encoded.version /*, meta*/) {
1167            Ok(decoded) => decoded,
1168            Err(e) => return Err(e),
1169        };
1170
1171        // Decoding the meta
1172        let meta = match encoded.meta {
1173            Some(ui_meta) => match TransactionStatusMeta::try_from(ui_meta) {
1174                Ok(meta) => meta,
1175                Err(_) => return Err(DecodeError::InvalidData),
1176            },
1177            None => return Err(DecodeError::InvalidData),
1178        };
1179
1180        Ok(Self {
1181            transaction,
1182            meta,
1183        })
1184    }
1185
1186    fn build_json_accounts(
1187        self,
1188        max_supported_transaction_version: Option<u8>,
1189        show_rewards: bool,
1190    ) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
1191        let version = self.validate_version(max_supported_transaction_version)?;
1192
1193        let account_keys = match &self.transaction.message {
1194            VersionedMessage::Legacy(message) => parse_legacy_message_accounts(message),
1195            VersionedMessage::V0(message) => {
1196                let loaded_message =
1197                    LoadedMessage::new_borrowed(message, &self.meta.loaded_addresses);
1198                parse_v0_message_accounts(&loaded_message)
1199            }
1200        };
1201
1202        Ok(EncodedTransactionWithStatusMeta {
1203            transaction: EncodedTransaction::Accounts(UiAccountsList {
1204                signatures: self
1205                    .transaction
1206                    .signatures
1207                    .iter()
1208                    .map(ToString::to_string)
1209                    .collect(),
1210                account_keys,
1211            }),
1212            meta: Some(UiTransactionStatusMeta::build_simple(
1213                self.meta,
1214                show_rewards,
1215            )),
1216            version,
1217        })
1218    }
1219}
1220
1221
1222#[derive(Debug, PartialEq)]
1223pub enum DecodeError {
1224    InvalidEncoding,
1225    InvalidAccountKey,
1226    InvalidBlockhash,
1227    DecodeFailed,
1228    DeserializeFailed,
1229    ParseSignatureFailed(ParseSignatureError),
1230    ParseHashFailed(ParseHashError),
1231    ParsePubkeyFailed(ParsePubkeyError),
1232    NotImplemented,
1233    InvalidData,
1234    UnsupportedEncoding,
1235    UnsupportedVersion,
1236}
1237
1238impl fmt::Display for DecodeError {
1239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1240        match self {
1241            DecodeError::InvalidEncoding => write!(f, "Invalid encoding"),
1242            DecodeError::DecodeFailed => write!(f, "Decoding failed"),
1243            DecodeError::DeserializeFailed => write!(f, "Deserialization failed"),
1244            DecodeError::InvalidAccountKey => write!(f, "Invalid account key"),
1245            DecodeError::InvalidBlockhash => write!(f, "Invalid blockhash"),
1246            DecodeError::ParseSignatureFailed(err) => write!(f, "Failed to parse signature: {}", err),
1247            DecodeError::ParseHashFailed(err) => write!(f, "Failed to parse hash: {}", err),
1248            DecodeError::ParsePubkeyFailed(err) => write!(f, "Failed to parse pubkey: {}", err),
1249            DecodeError::NotImplemented => write!(f, "Not implemented"),
1250            DecodeError::InvalidData => write!(f, "Invalid data"),
1251            DecodeError::UnsupportedEncoding => write!(f, "Encoding is not supported"),
1252            DecodeError::UnsupportedVersion => write!(f, "Transaction version is not supported"),
1253        }
1254    }
1255}
1256
1257impl Error for DecodeError {}
1258
1259impl From<ParsePubkeyError> for DecodeError {
1260    fn from(err: ParsePubkeyError) -> Self {
1261        DecodeError::ParsePubkeyFailed(err)
1262    }
1263}
1264
1265
1266
1267
1268
1269pub trait Decodable {
1270    type Encoded;
1271    type Decoded;
1272    fn decode(encoded: &Self::Encoded) -> Result<Self::Decoded, DecodeError>;
1273}
1274
1275impl Decodable for Message {
1276    type Encoded = UiMessage;
1277    type Decoded = Message;
1278
1279    fn decode(encoded: &Self::Encoded) -> Result<Self::Decoded, DecodeError> {
1280        match encoded {
1281            UiMessage::Raw(raw_message) => {
1282                let header = raw_message.header;
1283                let account_keys: Result<Vec<Pubkey>, _> = raw_message
1284                    .account_keys
1285                    .iter()
1286                    .map(|key_str| key_str.parse())
1287                    .collect();
1288                let account_keys = account_keys?;
1289                let recent_blockhash = Hash::from_str(&raw_message.recent_blockhash)
1290                    .map_err(|err| DecodeError::ParseHashFailed(err))?;
1291                let instructions: Vec<CompiledInstruction> = raw_message
1292                    .instructions
1293                    .iter()
1294                    // .map(|ui_instruction| (*ui_instruction).into() )
1295                    .map(|ui_instruction| ui_instruction.clone().into() )
1296                    .collect();
1297
1298                Ok(Message {
1299                    header,
1300                    account_keys,
1301                    recent_blockhash,
1302                    instructions,
1303                })
1304            }
1305            UiMessage::Parsed(_) => {
1306                Err(DecodeError::UnsupportedEncoding)
1307            }
1308        }
1309    }
1310}
1311
1312impl Decodable for Transaction {
1313    type Encoded = EncodedTransaction;
1314    type Decoded = Transaction;
1315
1316    fn decode(encoded: &Self::Encoded) -> Result<Self::Decoded, DecodeError> {
1317        match encoded {
1318            EncodedTransaction::LegacyBinary(s) | EncodedTransaction::Binary(s, TransactionBinaryEncoding::Base58) => {
1319                // let data = bs58::decode(s).into_vec()?;
1320                let data = bs58::decode(s)
1321                    .into_vec()
1322                    .map_err(|_| DecodeError::DeserializeFailed)?;
1323                // let transaction: Transaction = bincode::deserialize(&data)?;
1324                let transaction: Transaction = bincode::deserialize(&data)
1325                    .map_err(|_| DecodeError::DeserializeFailed)?;
1326                Ok(transaction)
1327            }
1328            EncodedTransaction::Binary(s, TransactionBinaryEncoding::Base64) => {
1329                // let data = base64::decode(s)?;
1330                let data = base64::decode(s)
1331                    .map_err(|_| DecodeError::DeserializeFailed)?;
1332                // let transaction: Transaction = bincode::deserialize(&data)?;
1333                let transaction: Transaction = bincode::deserialize(&data)
1334                    .map_err(|_| DecodeError::DeserializeFailed)?;
1335                Ok(transaction)
1336            }
1337            EncodedTransaction::Json(ui_transaction) => {
1338                let message = Message::decode(&ui_transaction.message)?;
1339                let signatures: Result<Vec<Signature>, ParseSignatureError> = ui_transaction.signatures.iter()
1340                    .map(|s| Signature::from_str(s))
1341                    .collect();
1342                let signatures = match signatures {
1343                    Ok(signatures) => signatures,
1344                    Err(error) => return Err(DecodeError::ParseSignatureFailed(error)),
1345                };
1346                Ok(Transaction {
1347                    signatures,
1348                    message,
1349                })
1350            }
1351            EncodedTransaction::Accounts(_) => {
1352                Err(DecodeError::UnsupportedEncoding)
1353            }
1354        }
1355    }
1356}
1357
1358
1359
1360pub trait DecodableWithMeta {
1361    type Encoded;
1362    type Decoded;
1363    fn decode_with_meta(
1364        encoded: Self::Encoded,
1365        encoding: UiTransactionEncoding,
1366        version: Option<TransactionVersion>
1367        // meta: Option<&TransactionStatusMeta>,
1368    ) -> Result<Self::Decoded, DecodeError>;
1369    // fn json_decode(ui_transaction: UiTransaction) -> Result<Self::Decoded, DecodeError>;
1370    fn json_decode(encoded: Self::Encoded, version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError>;
1371}
1372
1373impl DecodableWithMeta for VersionedTransaction {
1374    type Encoded = EncodedTransaction;
1375    type Decoded = VersionedTransaction;
1376
1377    fn decode_with_meta(
1378        encoded: Self::Encoded,
1379        decoding: UiTransactionEncoding,
1380        version: Option<TransactionVersion>
1381    ) -> Result<Self::Decoded, DecodeError> {
1382        match decoding {
1383            UiTransactionEncoding::Binary | UiTransactionEncoding::Base58 => {
1384                if let EncodedTransaction::LegacyBinary(encoded_string) = encoded {
1385                    let decoded_bytes = bs58::decode(encoded_string).into_vec().unwrap();
1386                    let decoded: Self::Decoded =
1387                        bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
1388                    Ok(decoded)
1389                } else {
1390                    Err(DecodeError::UnsupportedEncoding)
1391                }
1392            }
1393            UiTransactionEncoding::Base64 => {
1394                if let EncodedTransaction::Binary(encoded_string, _) = encoded {
1395                    let decoded_bytes = base64::decode(encoded_string).unwrap();
1396                    let decoded: Self::Decoded =
1397                        bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
1398                    Ok(decoded)
1399                } else {
1400                    Err(DecodeError::UnsupportedEncoding)
1401                }
1402            }
1403            UiTransactionEncoding::Json => Self::json_decode(encoded, version),
1404            UiTransactionEncoding::JsonParsed => Err(DecodeError::UnsupportedEncoding),
1405        }
1406    }
1407
1408    // fn decode_with_meta(
1409    //     encoded: EncodedTransaction,
1410    //     encoding: UiTransactionEncoding,
1411    //     // meta: Option<&TransactionStatusMeta>,
1412    // ) -> Result<Self::Decoded, DecodeError> {
1413    //     let (signatures, message) = match encoded {
1414    //         // EncodedTransaction::Json(ui_transaction) => {
1415    //         EncodedTransaction::Json(_) => {
1416    //             return Self::json_decode(encoded);
1417    //         }
1418    //         // EncodedTransaction::JsonParsed(ui_transaction) => {
1419    //         //     let signatures = ui_transaction
1420    //         //         .signatures
1421    //         //         .iter()
1422    //         //         .map(|s| s.parse::<Signature>())
1423    //         //         .collect::<Result<Vec<_>, _>>()
1424    //         //         .map_err(|_| DecodeError::InvalidData)?;
1425    //         //
1426    //         //     let message = match encoding {
1427    //         //         UiTransactionEncoding::JsonParsed => {
1428    //         //             let message = VersionedMessage::decode(ui_transaction.message)?;
1429    //         //             match (&message, meta) {
1430    //         //                 (VersionedMessage::V0(message), Some(meta)) => {
1431    //         //                     message.decode_with_meta(meta)?
1432    //         //                 }
1433    //         //                 _ => message,
1434    //         //             }
1435    //         //         }
1436    //         //         _ => return Err(DecodeError::InvalidEncoding),
1437    //         //     };
1438    //         //
1439    //         //     (signatures, message)
1440    //         // }
1441    //         EncodedTransaction::Accounts(_) => return Err(DecodeError::InvalidEncoding),
1442    //         _ => {}
1443    //     };
1444    //
1445    //     Ok(Self {
1446    //         signatures,
1447    //         message,
1448    //     })
1449    // }
1450
1451    // fn json_encode(&self) -> Self::Encoded {
1452    //     EncodedTransaction::Json(UiTransaction {
1453    //         signatures: self.signatures.iter().map(ToString::to_string).collect(),
1454    //         message: match &self.message {
1455    //             VersionedMessage::Legacy(message) => message.encode(UiTransactionEncoding::Json),
1456    //             VersionedMessage::V0(message) => message.json_encode(),
1457    //         },
1458    //     })
1459    // }
1460
1461    // VersionedMessage::decode(&ui_transaction.message)?
1462
1463    fn json_decode(encoded: Self::Encoded, version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError> {
1464        if let EncodedTransaction::Json(ui_transaction) = encoded {
1465            let signatures = ui_transaction
1466                .signatures
1467                .iter()
1468                .map(|s| s.parse::<Signature>())
1469                .collect::<Result<Vec<_>, _>>()
1470                .map_err(|err| DecodeError::ParseSignatureFailed(err))?;
1471
1472            let message = match ui_transaction.message {
1473                UiMessage::Raw(_) => {
1474                    match version {
1475                        Some(TransactionVersion::Number(0)) => {
1476                            // Handle Version 0 message decoding for raw messages
1477                            let v0_message = v0::Message::json_decode(ui_transaction.message, version)?;
1478                            VersionedMessage::V0(v0_message)
1479                        }
1480                        Some(TransactionVersion::Legacy(_)) | None => {
1481                            // Default to legacy message decoding for raw messages
1482                            let legacy_message = Message::decode(&ui_transaction.message)?;
1483                            VersionedMessage::Legacy(legacy_message)
1484                        }
1485                        // Add additional cases here for other versions as needed
1486                        _ => {
1487                            // Handle other versions or return an error if not supported
1488                            return Err(DecodeError::UnsupportedVersion);
1489                        }
1490                    }
1491                }
1492                UiMessage::Parsed(_) => {
1493                    return Err(DecodeError::UnsupportedEncoding);
1494                }
1495            };
1496
1497            Ok(Self {
1498                signatures,
1499                message,
1500            })
1501        } else {
1502            Err(DecodeError::UnsupportedEncoding)
1503        }
1504    }
1505
1506    // fn json_decode(ui_transaction: UiTransaction) -> Result<Self::Decoded, DecodeError> {
1507    // fn json_decode(encoded: Self::Encoded) -> Result<Self::Decoded, DecodeError> {
1508    //     let ui_transaction = match encoded {
1509    //         EncodedTransaction::Json(ui_transaction) => ui_transaction,
1510    //         _ => return Err(DecodeError::InvalidData),
1511    //     };
1512    //
1513    //     let signatures = ui_transaction
1514    //         .signatures
1515    //         .iter()
1516    //         .map(|s| s.parse::<Signature>())
1517    //         .collect::<Result<Vec<_>, _>>()
1518    //         .map_err(|_| DecodeError::InvalidData)?;
1519    //
1520    //     let message = VersionedMessage::decode(ui_transaction.message)?;
1521    //     Ok(Self {
1522    //         signatures,
1523    //         message,
1524    //     })
1525    // }
1526}
1527
1528
1529impl TransactionWithStatusMeta {
1530    pub fn encode(
1531        self,
1532        encoding: UiTransactionEncoding,
1533        max_supported_transaction_version: Option<u8>,
1534        show_rewards: bool,
1535    ) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
1536        match self {
1537            Self::MissingMetadata(ref transaction) => Ok(EncodedTransactionWithStatusMeta {
1538                version: None,
1539                transaction: transaction.encode(encoding),
1540                meta: None,
1541            }),
1542            Self::Complete(tx_with_meta) => {
1543                tx_with_meta.encode(encoding, max_supported_transaction_version, show_rewards)
1544            }
1545        }
1546    }
1547
1548    pub fn decode(
1549        encoded: EncodedTransactionWithStatusMeta,
1550        encoding: UiTransactionEncoding,
1551    ) -> Result<Self, DecodeError> {
1552        match encoded.meta {
1553            Some(_) => {
1554                let complete = VersionedTransactionWithStatusMeta::decode(encoded, encoding /*, None*/)?;
1555                Ok(Self::Complete(complete))
1556            },
1557            None => {
1558                let transaction = Transaction::decode(&encoded.transaction)?;
1559                Ok(Self::MissingMetadata(transaction))
1560            }
1561        }
1562    }
1563
1564    // pub fn decode(
1565    //     encoded: EncodedTransactionWithStatusMeta,
1566    //     encoding: UiTransactionEncoding,
1567    //     // max_supported_transaction_version: Option<u8>,
1568    //     // show_rewards: bool,
1569    // ) -> Result<Self, DecodeError> {
1570    //     match encoded {
1571    //         EncodedTransactionWithStatusMeta::MissingMetadata(encoded_transaction) => {
1572    //             let transaction = Transaction::decode(&encoded_transaction)?;
1573    //
1574    //             Ok(Self::MissingMetadata(transaction))
1575    //         },
1576    //         EncodedTransactionWithStatusMeta::Complete(encoded_tx_with_meta) => {
1577    //             let tx_with_meta = VersionedTransactionWithStatusMeta::decode(
1578    //                 encoded_tx_with_meta,
1579    //                 encoding,
1580    //                 // max_supported_transaction_version,
1581    //                 // show_rewards
1582    //             )?;
1583    //
1584    //             Ok(Self::Complete(tx_with_meta))
1585    //         }
1586    //     }
1587    // }
1588
1589    pub fn transaction_signature(&self) -> &Signature {
1590        match self {
1591            Self::MissingMetadata(transaction) => &transaction.signatures[0],
1592            Self::Complete(VersionedTransactionWithStatusMeta { transaction, .. }) => {
1593                &transaction.signatures[0]
1594            }
1595        }
1596    }
1597
1598    fn build_json_accounts(
1599        self,
1600        max_supported_transaction_version: Option<u8>,
1601        show_rewards: bool,
1602    ) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
1603        match self {
1604            Self::MissingMetadata(ref transaction) => Ok(EncodedTransactionWithStatusMeta {
1605                version: None,
1606                transaction: transaction.build_json_accounts(),
1607                meta: None,
1608            }),
1609            Self::Complete(tx_with_meta) => {
1610                tx_with_meta.build_json_accounts(max_supported_transaction_version, show_rewards)
1611            }
1612        }
1613    }
1614}
1615
1616
1617// impl From<UiTransactionStatusMeta> for TransactionStatusMeta {
1618//     fn from(meta: UiTransactionStatusMeta) -> Self {
1619//         Self {
1620//             status: meta.status,
1621//             fee: meta.fee,
1622//             pre_balances: meta.pre_balances,
1623//             post_balances: meta.post_balances,
1624//             inner_instructions: meta.inner_instructions.into_option().map(|ixs|
1625//                 ixs.into_iter().map(Into::into).collect()
1626//             ),
1627//             log_messages: meta.log_messages.into_option(),
1628//             pre_token_balances: meta.pre_token_balances.into_option().map(|balance|
1629//                 balance.into_iter().map(Into::into).collect()
1630//             ),
1631//             post_token_balances: meta.post_token_balances.into_option().map(|balance|
1632//                 balance.into_iter().map(Into::into).collect()
1633//             ),
1634//             rewards: meta.rewards.into_option(),
1635//             loaded_addresses: LoadedAddresses::from(meta.loaded_addresses.into_option().unwrap_or_default()),
1636//             return_data: meta.return_data.into_option().map(|return_data| return_data.into()),
1637//             compute_units_consumed: meta.compute_units_consumed.into_option(),
1638//         }
1639//     }
1640// }
1641
1642impl TryFrom<UiTransactionStatusMeta> for TransactionStatusMeta {
1643    type Error = ConversionError;
1644
1645    fn try_from(meta: UiTransactionStatusMeta) -> Result<Self, Self::Error> {
1646        let inner_instructions: Option<Vec<InnerInstructions>> = match meta.inner_instructions {
1647            OptionSerializer::Some(ui_inner_instructions) => {
1648                let inner_instructions_result: Result<Vec<_>, _> = ui_inner_instructions
1649                    .into_iter()
1650                    .map(|ui_inner_instruction| InnerInstructions::try_from(ui_inner_instruction))
1651                    .collect();
1652
1653                match inner_instructions_result {
1654                    Ok(inner_instructions) => Some(inner_instructions),
1655                    Err(e) => return Err(e),
1656                }
1657            }
1658            _ => None,
1659        };
1660
1661        let pre_token_balances: Option<Vec<TransactionTokenBalance>> = match meta.pre_token_balances {
1662            OptionSerializer::Some(ui_pre_token_balances) => {
1663                let pre_token_balances: Vec<_> = ui_pre_token_balances
1664                    .into_iter()
1665                    .map(TransactionTokenBalance::from)
1666                    .collect();
1667
1668                Some(pre_token_balances)
1669            }
1670            _ => None,
1671        };
1672
1673        let post_token_balances: Option<Vec<TransactionTokenBalance>> = match meta.post_token_balances {
1674            OptionSerializer::Some(ui_post_token_balances) => {
1675                let post_token_balances: Vec<_> = ui_post_token_balances
1676                    .into_iter()
1677                    .map(TransactionTokenBalance::from)
1678                    .collect();
1679
1680                Some(post_token_balances)
1681            }
1682            _ => None,
1683        };
1684
1685        let return_data: Option<TransactionReturnData> = match meta.return_data {
1686            OptionSerializer::Some(ui_return_data) => {
1687                let return_data = TransactionReturnData::try_from(ui_return_data)?;
1688                Some(return_data)
1689            }
1690            _ => None,
1691        };
1692
1693        // let loaded_addresses: LoadedAddresses = match LoadedAddresses::try_from(&meta.loaded_addresses) {
1694        //     Ok(loaded_addresses) => loaded_addresses,
1695        //     Err(_) => return Err(ConversionError::InvalidProgramId),
1696        // };
1697
1698        let loaded_addresses: LoadedAddresses = match &meta.loaded_addresses {
1699            OptionSerializer::Some(ui_loaded_addresses) => {
1700                match LoadedAddresses::try_from(ui_loaded_addresses) {
1701                    Ok(loaded_addresses) => loaded_addresses,
1702                    Err(_) => return Err(ConversionError::InvalidProgramId),
1703                }
1704                // match (*ui_loaded_addresses).into() {
1705                //     Ok(loaded_addresses) => loaded_addresses,
1706                //     Err(_) => return Err(ConversionError::InvalidProgramId),
1707                // }
1708            }
1709            _ => return Err(ConversionError::InvalidProgramId),
1710        };
1711
1712        let compute_units_consumed: Option<u64> = match meta.compute_units_consumed {
1713            OptionSerializer::Some(cuc) => Some(cuc),
1714            _ => None,
1715        };
1716
1717        Ok(Self {
1718            status: meta.status,
1719            fee: meta.fee,
1720            pre_balances: meta.pre_balances,
1721            post_balances: meta.post_balances,
1722            inner_instructions,
1723            log_messages: match meta.log_messages {
1724                OptionSerializer::Some(logs) => Some(logs),
1725                _ => None,
1726            },
1727            pre_token_balances,
1728            post_token_balances,
1729            rewards: match meta.rewards {
1730                OptionSerializer::Some(rewards) => Some(rewards),
1731                _ => None,
1732            },
1733            loaded_addresses,
1734            return_data,
1735            compute_units_consumed,
1736        })
1737    }
1738}
1739
1740
1741
1742// impl From<UiInnerInstructions> for InnerInstructions {
1743//     fn from(ui_inner_instructions: UiInnerInstructions) -> Self {
1744//         Self {
1745//             index: ui_inner_instructions.index,
1746//             instructions: ui_inner_instructions
1747//                 .instructions
1748//                 .into_iter()
1749//                 .map(|ix| match ix {
1750//                     UiInstruction::Compiled(ui_compiled) => CompiledInstruction::from(ui_compiled),
1751//                     _ => panic!("Cannot convert from UiInstruction::Parsed to CompiledInstruction"),
1752//                 })
1753//                 .collect(),
1754//         }
1755//     }
1756// }
1757
1758impl TryFrom<UiInnerInstructions> for InnerInstructions {
1759    type Error = ConversionError;
1760
1761    fn try_from(ui_inner_instructions: UiInnerInstructions) -> Result<Self, Self::Error> {
1762        let instructions_result: Result<Vec<_>, _> = ui_inner_instructions
1763            .instructions
1764            .into_iter()
1765            .map(|ix| match ix {
1766                // UiInstruction::Compiled(ui_compiled) => Ok(CompiledInstruction::from(ui_compiled)),
1767                UiInstruction::Compiled(ui_compiled) => Ok(InnerInstruction::from(ui_compiled)),
1768                _ => Err(ConversionError::UnsupportedInstructionFormat),
1769            })
1770            .collect();
1771
1772        match instructions_result {
1773            Ok(instructions) => Ok(Self {
1774                index: ui_inner_instructions.index,
1775                instructions,
1776            }),
1777            Err(e) => Err(e),
1778        }
1779    }
1780}
1781
1782impl From<UiCompiledInstruction> for InnerInstruction {
1783    fn from(ui_compiled_instruction: UiCompiledInstruction) -> Self {
1784        Self {
1785            instruction: CompiledInstruction::from(ui_compiled_instruction.clone()), // Clone is needed if CompiledInstruction::from consumes its argument
1786            stack_height: ui_compiled_instruction.stack_height,
1787        }
1788    }
1789}
1790
1791impl From<UiCompiledInstruction> for CompiledInstruction {
1792    fn from(ui_compiled_instruction: UiCompiledInstruction) -> Self {
1793        Self {
1794            program_id_index: ui_compiled_instruction.program_id_index,
1795            accounts: ui_compiled_instruction.accounts,
1796            data: bs58::decode(ui_compiled_instruction.data).into_vec().unwrap(),
1797        }
1798    }
1799}
1800
1801impl From<UiTransactionTokenBalance> for TransactionTokenBalance {
1802    fn from(token_balance: UiTransactionTokenBalance) -> Self {
1803        Self {
1804            account_index: token_balance.account_index,
1805            mint: token_balance.mint,
1806            ui_token_amount: token_balance.ui_token_amount,
1807            owner: match token_balance.owner {
1808                OptionSerializer::Some(owner) => owner,
1809                _ => String::new(),
1810            },
1811            program_id: match token_balance.program_id {
1812                OptionSerializer::Some(program_id) => program_id,
1813                _ => String::new(),
1814            },
1815        }
1816    }
1817}
1818
1819#[derive(Debug)]
1820pub enum ConversionError {
1821    InvalidProgramId,
1822    InvalidData,
1823    UnsupportedInstructionFormat,
1824}
1825
1826impl fmt::Display for ConversionError {
1827    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1828        match self {
1829            Self::InvalidProgramId => write!(f, "Invalid program id"),
1830            Self::InvalidData => write!(f, "Invalid data"),
1831            Self::UnsupportedInstructionFormat => write!(f, "Cannot convert from UiInstruction::Parsed to CompiledInstruction"),
1832        }
1833    }
1834}
1835
1836impl Error for ConversionError {} // Implements the standard Error trait
1837
1838impl TryFrom<UiTransactionReturnData> for TransactionReturnData {
1839    type Error = ConversionError;
1840
1841    fn try_from(ui_return_data: UiTransactionReturnData) -> Result<Self, Self::Error> {
1842        let program_id = Pubkey::from_str(&ui_return_data.program_id)
1843            .map_err(|_| ConversionError::InvalidProgramId)?;
1844
1845        let data = base64::decode(&ui_return_data.data.0)
1846            .map_err(|_| ConversionError::InvalidData)?;
1847
1848        Ok(Self { program_id, data })
1849    }
1850}
1851
1852// impl From<&UiLoadedAddresses> for Result<LoadedAddresses, ParsePubkeyError> {
1853//     fn from(ui_loaded_addresses: &UiLoadedAddresses) -> Self {
1854//         let writable: Result<Vec<Pubkey>, _> = ui_loaded_addresses
1855//             .writable
1856//             .iter()
1857//             .map(|s| Pubkey::from_str(s))
1858//             .collect();
1859//
1860//         let readonly: Result<Vec<Pubkey>, _> = ui_loaded_addresses
1861//             .readonly
1862//             .iter()
1863//             .map(|s| Pubkey::from_str(s))
1864//             .collect();
1865//
1866//         Ok(LoadedAddresses {
1867//             writable: writable?,
1868//             readonly: readonly?,
1869//         })
1870//     }
1871// }
1872
1873// impl From<&UiLoadedAddresses> for LoadedAddresses {
1874//     fn from(ui_loaded_addresses: &UiLoadedAddresses) -> Self {
1875//         Self {
1876//             writable: ui_loaded_addresses
1877//                 .writable
1878//                 .iter()
1879//                 .filter_map(|s| s.parse().ok())
1880//                 .collect(),
1881//             readonly: ui_loaded_addresses
1882//                 .readonly
1883//                 .iter()
1884//                 .filter_map(|s| s.parse().ok())
1885//                 .collect(),
1886//         }
1887//     }
1888// }
1889
1890impl TryFrom<&UiLoadedAddresses> for LoadedAddresses {
1891    type Error = ParsePubkeyError;
1892
1893    fn try_from(ui_loaded_addresses: &UiLoadedAddresses) -> Result<Self, Self::Error> {
1894        let writable: Result<Vec<Pubkey>, _> = ui_loaded_addresses
1895            .writable
1896            .iter()
1897            .map(|s| Pubkey::from_str(s))
1898            .collect();
1899
1900        let readonly: Result<Vec<Pubkey>, _> = ui_loaded_addresses
1901            .readonly
1902            .iter()
1903            .map(|s| Pubkey::from_str(s))
1904            .collect();
1905
1906        Ok(Self {
1907            writable: writable?,
1908            readonly: readonly?,
1909        })
1910    }
1911}
1912
1913
1914
1915
1916impl TryFrom<ConfirmedBlock> for VersionedConfirmedBlock {
1917    type Error = ConvertBlockError;
1918
1919    fn try_from(block: ConfirmedBlock) -> Result<Self, Self::Error> {
1920        let expected_transaction_count = block.transactions.len();
1921
1922        let txs: Vec<_> = block
1923            .transactions
1924            .into_iter()
1925            .filter_map(|tx| match tx {
1926                TransactionWithStatusMeta::MissingMetadata(_) => None,
1927                TransactionWithStatusMeta::Complete(tx) => Some(tx),
1928            })
1929            .collect();
1930
1931        if txs.len() != expected_transaction_count {
1932            return Err(ConvertBlockError::TransactionsMissing(
1933                expected_transaction_count,
1934                txs.len(),
1935            ));
1936        }
1937
1938        Ok(Self {
1939            previous_blockhash: block.previous_blockhash,
1940            blockhash: block.blockhash,
1941            parent_slot: block.parent_slot,
1942            transactions: txs,
1943            rewards: block.rewards,
1944            block_time: block.block_time,
1945            block_height: block.block_height,
1946        })
1947    }
1948}
1949
1950impl ConfirmedBlock {
1951    pub fn encode_with_options(
1952        self,
1953        encoding: UiTransactionEncoding,
1954        options: BlockEncodingOptions,
1955    ) -> Result<UiConfirmedBlock, EncodeError> {
1956        let (transactions, signatures) = match options.transaction_details {
1957            TransactionDetails::Full => (
1958                Some(
1959                    self.transactions
1960                        .into_iter()
1961                        .map(|tx_with_meta| {
1962                            tx_with_meta.encode(
1963                                encoding,
1964                                options.max_supported_transaction_version,
1965                                options.show_rewards,
1966                            )
1967                        })
1968                        .collect::<Result<Vec<_>, _>>()?,
1969                ),
1970                None,
1971            ),
1972            TransactionDetails::Signatures => (
1973                None,
1974                Some(
1975                    self.transactions
1976                        .into_iter()
1977                        .map(|tx_with_meta| tx_with_meta.transaction_signature().to_string())
1978                        .collect(),
1979                ),
1980            ),
1981            TransactionDetails::None => (None, None),
1982            TransactionDetails::Accounts => (
1983                Some(
1984                    self.transactions
1985                        .into_iter()
1986                        .map(|tx_with_meta| {
1987                            tx_with_meta.build_json_accounts(
1988                                options.max_supported_transaction_version,
1989                                options.show_rewards,
1990                            )
1991                        })
1992                        .collect::<Result<Vec<_>, _>>()?,
1993                ),
1994                None,
1995            ),
1996        };
1997        Ok(UiConfirmedBlock {
1998            previous_blockhash: self.previous_blockhash,
1999            blockhash: self.blockhash,
2000            parent_slot: self.parent_slot,
2001            transactions,
2002            signatures,
2003            rewards: if options.show_rewards {
2004                Some(self.rewards)
2005            } else {
2006                None
2007            },
2008            block_time: self.block_time,
2009            block_height: self.block_height,
2010        })
2011    }
2012
2013    pub fn decode_with_options(
2014        ui_confirmed_block: UiConfirmedBlock,
2015        encoding: UiTransactionEncoding,
2016        options: BlockEncodingOptions,
2017    ) -> Result<Self, DecodeError> {
2018        let transactions = match options.transaction_details {
2019            TransactionDetails::Full => {
2020                let transactions = ui_confirmed_block
2021                    .transactions
2022                    .ok_or(DecodeError::InvalidEncoding)?
2023                    .into_iter()
2024                    .map(|encoded_tx_with_meta| {
2025                        TransactionWithStatusMeta::decode(encoded_tx_with_meta, encoding)
2026                    })
2027                    .collect::<Result<Vec<_>, _>>()?;
2028                transactions
2029            }
2030            TransactionDetails::Signatures => {
2031                let signatures = ui_confirmed_block
2032                    .signatures
2033                    .ok_or(DecodeError::InvalidEncoding)?;
2034                // Implement a method or mechanism to retrieve transactions using signatures
2035                return Err(DecodeError::NotImplemented);
2036            }
2037            TransactionDetails::None => Vec::new(),
2038            TransactionDetails::Accounts => {
2039                let transactions = ui_confirmed_block
2040                    .transactions
2041                    .ok_or(DecodeError::InvalidEncoding)?
2042                    .into_iter()
2043                    .map(|encoded_tx_with_meta| {
2044                        TransactionWithStatusMeta::decode(encoded_tx_with_meta, encoding)
2045                    })
2046                    .collect::<Result<Vec<_>, _>>()?;
2047                transactions
2048            }
2049        };
2050
2051        Ok(ConfirmedBlock {
2052            previous_blockhash: ui_confirmed_block.previous_blockhash,
2053            blockhash: ui_confirmed_block.blockhash,
2054            parent_slot: ui_confirmed_block.parent_slot,
2055            transactions,
2056            rewards: ui_confirmed_block
2057                .rewards
2058                .unwrap_or_default(),
2059            block_time: ui_confirmed_block.block_time,
2060            block_height: ui_confirmed_block.block_height,
2061        })
2062    }
2063}
2064
2065impl From<EncodedConfirmedBlock> for UiConfirmedBlock {
2066    fn from(block: EncodedConfirmedBlock) -> Self {
2067        Self {
2068            previous_blockhash: block.previous_blockhash,
2069            blockhash: block.blockhash,
2070            parent_slot: block.parent_slot,
2071            transactions: Some(block.transactions),
2072            signatures: None, // Set to None since it's not available in EncodedConfirmedBlock
2073            rewards: Some(block.rewards),
2074            block_time: block.block_time,
2075            block_height: block.block_height,
2076        }
2077    }
2078}
2079
2080impl From<VersionedTransactionWithStatusMeta> for TransactionWithStatusMeta {
2081    fn from(item: VersionedTransactionWithStatusMeta) -> Self {
2082        TransactionWithStatusMeta::Complete(item)
2083    }
2084}