solana_binary_encoder/
convert.rs

1
2use {
3    crate::{
4        // message_header::MessageHeader,
5        transaction_status::{ConfirmedBlock, Reward},
6        transaction_status::{
7            TransactionWithStatusMeta,
8            VersionedTransactionWithStatusMeta,
9            TransactionStatusMeta,
10            InnerInstruction,
11            InnerInstructions,
12            TransactionTokenBalance,
13            VersionedConfirmedBlock,
14            TransactionByAddrInfo,
15            ConfirmedTransactionWithStatusMeta,
16        },
17        // transaction_error::TransactionError,
18        // account_decoder::UiTokenAmount,
19        // transaction_context::TransactionReturnData,
20        // versioned_transaction::VersionedTransaction,
21        // versioned_message::VersionedMessage,
22        // message::{Message as LegacyMessage},
23        // message_v0::{Message as MessageV0, MessageAddressTableLookup},
24        // instruction::{CompiledInstruction, InstructionError},
25        parse_token::real_number_string_trimmed,
26        // loaded_addresses::LoadedAddresses,
27        // transaction::Transaction,
28        // reward_type::RewardType,
29        // signature::Signature,
30        // pubkey::Pubkey,
31        // hash::Hash,
32    },
33    solana_sdk::{
34        message::{
35            v0::{
36                self,
37                LoadedAddresses,
38                MessageAddressTableLookup,
39            },
40            Message,
41            MessageHeader,
42            VersionedMessage,
43        },
44        transaction::{
45            TransactionError,
46            VersionedTransaction,
47            Transaction,
48        },
49        instruction::{CompiledInstruction, InstructionError},
50        transaction_context::TransactionReturnData,
51        pubkey::Pubkey,
52        reward_type::RewardType,
53        signature::Signature,
54        hash::Hash,
55        clock::{UnixTimestamp},
56    },
57    solana_account_decoder::parse_token::UiTokenAmount,
58    std::{
59        convert::{
60            TryFrom,
61            TryInto,
62        },
63        str::FromStr,
64    },
65};
66
67#[allow(clippy::derive_partial_eq_without_eq)]
68pub mod generated {
69    // include!("encoder.proto/solana.storage.confirmed_block.rs");
70    include!("proto/solana.storage.confirmed_block.rs");
71}
72
73pub mod tx_by_addr {
74    include!("proto/solana.storage.transaction_by_addr.rs");
75    // include!(concat!(
76    //     env!("OUT_DIR"),
77    //     "/solana.storage.transaction_by_addr.rs"
78    // ));
79}
80
81impl From<MessageHeader> for generated::MessageHeader {
82    fn from(value: MessageHeader) -> Self {
83        Self {
84            num_required_signatures: value.num_required_signatures as u32,
85            num_readonly_signed_accounts: value.num_readonly_signed_accounts as u32,
86            num_readonly_unsigned_accounts: value.num_readonly_unsigned_accounts as u32,
87        }
88    }
89}
90
91impl TryFrom<generated::ConfirmedBlock> for ConfirmedBlock {
92    type Error = bincode::Error;
93    fn try_from(
94        confirmed_block: generated::ConfirmedBlock,
95    ) -> std::result::Result<Self, Self::Error> {
96        let generated::ConfirmedBlock {
97            previous_blockhash,
98            blockhash,
99            parent_slot,
100            transactions,
101            rewards,
102            block_time,
103            block_height,
104        } = confirmed_block;
105
106        Ok(Self {
107            previous_blockhash,
108            blockhash,
109            parent_slot,
110            transactions: transactions
111                .into_iter()
112                .map(|tx| tx.try_into())
113                .collect::<std::result::Result<Vec<_>, Self::Error>>()?,
114            rewards: rewards.into_iter().map(|r| r.into()).collect(),
115            block_time: block_time.map(|generated::UnixTimestamp { timestamp }| timestamp),
116            block_height: block_height.map(|generated::BlockHeight { block_height }| block_height),
117        })
118    }
119}
120
121impl From<generated::Reward> for Reward {
122    fn from(reward: generated::Reward) -> Self {
123        Self {
124            pubkey: reward.pubkey,
125            lamports: reward.lamports,
126            post_balance: reward.post_balance,
127            reward_type: match reward.reward_type {
128                0 => None,
129                1 => Some(RewardType::Fee),
130                2 => Some(RewardType::Rent),
131                3 => Some(RewardType::Staking),
132                4 => Some(RewardType::Voting),
133                _ => None,
134            },
135            commission: reward.commission.parse::<u8>().ok(),
136        }
137    }
138}
139
140impl From<VersionedConfirmedBlock> for generated::ConfirmedBlock {
141    fn from(confirmed_block: VersionedConfirmedBlock) -> Self {
142        let VersionedConfirmedBlock {
143            previous_blockhash,
144            blockhash,
145            parent_slot,
146            transactions,
147            rewards,
148            block_time,
149            block_height,
150        } = confirmed_block;
151
152        Self {
153            previous_blockhash,
154            blockhash,
155            parent_slot,
156            transactions: transactions.into_iter().map(|tx| tx.into()).collect(),
157            rewards: rewards.into_iter().map(|r| r.into()).collect(),
158            block_time: block_time.map(|timestamp| generated::UnixTimestamp { timestamp }),
159            block_height: block_height.map(|block_height| generated::BlockHeight { block_height }),
160        }
161    }
162}
163
164impl From<TransactionWithStatusMeta> for generated::ConfirmedTransaction {
165    fn from(tx_with_meta: TransactionWithStatusMeta) -> Self {
166        match tx_with_meta {
167            TransactionWithStatusMeta::MissingMetadata(transaction) => Self {
168                transaction: Some(generated::Transaction::from(transaction)),
169                meta: None,
170            },
171            TransactionWithStatusMeta::Complete(tx_with_meta) => Self::from(tx_with_meta),
172        }
173    }
174}
175
176impl From<VersionedTransactionWithStatusMeta> for generated::ConfirmedTransaction {
177    fn from(value: VersionedTransactionWithStatusMeta) -> Self {
178        Self {
179            transaction: Some(value.transaction.into()),
180            meta: Some(value.meta.into()),
181        }
182    }
183}
184
185impl TryFrom<generated::ConfirmedTransaction> for TransactionWithStatusMeta {
186    type Error = bincode::Error;
187    fn try_from(value: generated::ConfirmedTransaction) -> std::result::Result<Self, Self::Error> {
188        let meta = value.meta.map(|meta| meta.try_into()).transpose()?;
189        let transaction = value.transaction.expect("transaction is required").into();
190        Ok(match meta {
191            Some(meta) => Self::Complete(VersionedTransactionWithStatusMeta { transaction, meta }),
192            None => Self::MissingMetadata(
193                transaction
194                    .into_legacy_transaction()
195                    .expect("meta is required for versioned transactions"),
196            ),
197        })
198    }
199}
200
201impl From<Transaction> for generated::Transaction {
202    fn from(value: Transaction) -> Self {
203        Self {
204            signatures: value
205                .signatures
206                .into_iter()
207                .map(|signature| <Signature as AsRef<[u8]>>::as_ref(&signature).into())
208                .collect(),
209            message: Some(value.message.into()),
210        }
211    }
212}
213
214impl From<VersionedTransaction> for generated::Transaction {
215    fn from(value: VersionedTransaction) -> Self {
216        Self {
217            signatures: value
218                .signatures
219                .into_iter()
220                .map(|signature| <Signature as AsRef<[u8]>>::as_ref(&signature).into())
221                .collect(),
222            message: Some(value.message.into()),
223        }
224    }
225}
226
227impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
228    fn from(value: TransactionStatusMeta) -> Self {
229        let TransactionStatusMeta {
230            status,
231            fee,
232            pre_balances,
233            post_balances,
234            inner_instructions,
235            log_messages,
236            pre_token_balances,
237            post_token_balances,
238            rewards,
239            loaded_addresses,
240            return_data,
241            compute_units_consumed,
242        } = value;
243        let err = match status {
244            Ok(()) => None,
245            Err(err) => Some(generated::TransactionError {
246                err: bincode::serialize(&err).expect("transaction error to serialize to bytes"),
247            }),
248        };
249        let inner_instructions_none = inner_instructions.is_none();
250        let inner_instructions = inner_instructions
251            .unwrap_or_default()
252            .into_iter()
253            .map(|ii| ii.into())
254            .collect();
255        let log_messages_none = log_messages.is_none();
256        let log_messages = log_messages.unwrap_or_default();
257        let pre_token_balances = pre_token_balances
258            .unwrap_or_default()
259            .into_iter()
260            .map(|balance| balance.into())
261            .collect();
262        let post_token_balances = post_token_balances
263            .unwrap_or_default()
264            .into_iter()
265            .map(|balance| balance.into())
266            .collect();
267        let rewards = rewards
268            .unwrap_or_default()
269            .into_iter()
270            .map(|reward| reward.into())
271            .collect();
272        let loaded_writable_addresses = loaded_addresses
273            .writable
274            .into_iter()
275            .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
276            .collect();
277        let loaded_readonly_addresses = loaded_addresses
278            .readonly
279            .into_iter()
280            .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
281            .collect();
282        let return_data_none = return_data.is_none();
283        let return_data = return_data.map(|return_data| return_data.into());
284
285        Self {
286            err,
287            fee,
288            pre_balances,
289            post_balances,
290            inner_instructions,
291            inner_instructions_none,
292            log_messages,
293            log_messages_none,
294            pre_token_balances,
295            post_token_balances,
296            rewards,
297            loaded_writable_addresses,
298            loaded_readonly_addresses,
299            return_data,
300            return_data_none,
301            compute_units_consumed,
302        }
303    }
304}
305
306impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
307    type Error = bincode::Error;
308
309    fn try_from(value: generated::TransactionStatusMeta) -> std::result::Result<Self, Self::Error> {
310        let generated::TransactionStatusMeta {
311            err,
312            fee,
313            pre_balances,
314            post_balances,
315            inner_instructions,
316            inner_instructions_none,
317            log_messages,
318            log_messages_none,
319            pre_token_balances,
320            post_token_balances,
321            rewards,
322            loaded_writable_addresses,
323            loaded_readonly_addresses,
324            return_data,
325            return_data_none,
326            compute_units_consumed,
327        } = value;
328        let status = match &err {
329            None => Ok(()),
330            Some(tx_error) => Err(bincode::deserialize(&tx_error.err)?),
331        };
332        let inner_instructions = if inner_instructions_none {
333            None
334        } else {
335            Some(
336                inner_instructions
337                    .into_iter()
338                    .map(|inner| inner.into())
339                    .collect(),
340            )
341        };
342        let log_messages = if log_messages_none {
343            None
344        } else {
345            Some(log_messages)
346        };
347        let pre_token_balances = Some(
348            pre_token_balances
349                .into_iter()
350                .map(|balance| balance.into())
351                .collect(),
352        );
353        let post_token_balances = Some(
354            post_token_balances
355                .into_iter()
356                .map(|balance| balance.into())
357                .collect(),
358        );
359        let rewards = Some(rewards.into_iter().map(|reward| reward.into()).collect());
360        let loaded_addresses = LoadedAddresses {
361            writable: loaded_writable_addresses
362                .into_iter()
363                .map(|key| Pubkey::new(&key))
364                .collect(),
365            readonly: loaded_readonly_addresses
366                .into_iter()
367                .map(|key| Pubkey::new(&key))
368                .collect(),
369        };
370        let return_data = if return_data_none {
371            None
372        } else {
373            return_data.map(|return_data| return_data.into())
374        };
375        Ok(Self {
376            status,
377            fee,
378            pre_balances,
379            post_balances,
380            inner_instructions,
381            log_messages,
382            pre_token_balances,
383            post_token_balances,
384            rewards,
385            loaded_addresses,
386            return_data,
387            compute_units_consumed,
388        })
389    }
390}
391
392impl From<ConfirmedTransactionWithStatusMeta> for generated::ConfirmedTransactionWithStatusMeta {
393    fn from(value: ConfirmedTransactionWithStatusMeta) -> Self {
394        Self {
395            slot: value.slot as u64, // Assuming Slot can be directly converted to u64
396            tx_with_meta: Some(value.tx_with_meta.into()), // Direct use of .into() due to existing From trait
397            // block_time: value.block_time.map(|bt| UnixTimestamp { seconds: bt }), // Assuming UnixTimestamp in the destination struct is compatible
398            block_time: value.block_time.map(|timestamp| generated::UnixTimestamp { timestamp }),
399        }
400    }
401}
402
403impl From<Message> for generated::Message {
404    fn from(message: Message) -> Self {
405        Self {
406            header: Some(message.header.into()),
407            account_keys: message
408                .account_keys
409                .iter()
410                .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(key).into())
411                .collect(),
412            recent_blockhash: message.recent_blockhash.to_bytes().into(),
413            instructions: message
414                .instructions
415                .into_iter()
416                .map(|ix| ix.into())
417                .collect(),
418            versioned: false,
419            address_table_lookups: vec![],
420        }
421    }
422}
423
424impl From<VersionedMessage> for generated::Message {
425    fn from(message: VersionedMessage) -> Self {
426        match message {
427            VersionedMessage::Legacy(message) => Self::from(message),
428            VersionedMessage::V0(message) => Self {
429                header: Some(message.header.into()),
430                account_keys: message
431                    .account_keys
432                    .iter()
433                    .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(key).into())
434                    .collect(),
435                recent_blockhash: message.recent_blockhash.to_bytes().into(),
436                instructions: message
437                    .instructions
438                    .into_iter()
439                    .map(|ix| ix.into())
440                    .collect(),
441                versioned: true,
442                address_table_lookups: message
443                    .address_table_lookups
444                    .into_iter()
445                    .map(|lookup| lookup.into())
446                    .collect(),
447            },
448        }
449    }
450}
451
452impl From<generated::Message> for VersionedMessage {
453    fn from(value: generated::Message) -> Self {
454        let header = value.header.expect("header is required").into();
455        let account_keys = value
456            .account_keys
457            .into_iter()
458            .map(|key| Pubkey::new(&key))
459            .collect();
460        let recent_blockhash = Hash::new(&value.recent_blockhash);
461        let instructions = value.instructions.into_iter().map(|ix| ix.into()).collect();
462        let address_table_lookups = value
463            .address_table_lookups
464            .into_iter()
465            .map(|lookup| lookup.into())
466            .collect();
467
468        if !value.versioned {
469            Self::Legacy(Message {
470                header,
471                account_keys,
472                recent_blockhash,
473                instructions,
474            })
475        } else {
476            Self::V0(v0::Message {
477                header,
478                account_keys,
479                recent_blockhash,
480                instructions,
481                address_table_lookups,
482            })
483        }
484    }
485}
486
487impl From<generated::Transaction> for VersionedTransaction {
488    fn from(value: generated::Transaction) -> Self {
489        Self {
490            signatures: value
491                .signatures
492                .into_iter()
493                .map(|x| Signature::new(&x))
494                .collect(),
495            message: value.message.expect("message is required").into(),
496        }
497    }
498}
499
500impl From<MessageAddressTableLookup> for generated::MessageAddressTableLookup {
501    fn from(lookup: MessageAddressTableLookup) -> Self {
502        Self {
503            account_key: <Pubkey as AsRef<[u8]>>::as_ref(&lookup.account_key).into(),
504            writable_indexes: lookup.writable_indexes,
505            readonly_indexes: lookup.readonly_indexes,
506        }
507    }
508}
509
510impl From<CompiledInstruction> for generated::CompiledInstruction {
511    fn from(value: CompiledInstruction) -> Self {
512        Self {
513            program_id_index: value.program_id_index as u32,
514            accounts: value.accounts,
515            data: value.data,
516        }
517    }
518}
519
520impl From<InnerInstruction> for generated::InnerInstruction {
521    fn from(value: InnerInstruction) -> Self {
522        Self {
523            program_id_index: value.instruction.program_id_index as u32,
524            accounts: value.instruction.accounts,
525            data: value.instruction.data,
526            stack_height: value.stack_height,
527        }
528    }
529}
530
531impl From<generated::InnerInstruction> for InnerInstruction {
532    fn from(value: generated::InnerInstruction) -> Self {
533        Self {
534            instruction: CompiledInstruction {
535                program_id_index: value.program_id_index as u8,
536                accounts: value.accounts,
537                data: value.data,
538            },
539            stack_height: value.stack_height,
540        }
541    }
542}
543
544impl From<InnerInstructions> for generated::InnerInstructions {
545    fn from(value: InnerInstructions) -> Self {
546        Self {
547            index: value.index as u32,
548            instructions: value.instructions.into_iter().map(|i| i.into()).collect(),
549        }
550    }
551}
552
553impl From<generated::InnerInstructions> for InnerInstructions {
554    fn from(value: generated::InnerInstructions) -> Self {
555        Self {
556            index: value.index as u8,
557            instructions: value.instructions.into_iter().map(|i| i.into()).collect(),
558        }
559    }
560}
561
562impl From<TransactionTokenBalance> for generated::TokenBalance {
563    fn from(value: TransactionTokenBalance) -> Self {
564        Self {
565            account_index: value.account_index as u32,
566            mint: value.mint,
567            ui_token_amount: Some(generated::UiTokenAmount {
568                ui_amount: value.ui_token_amount.ui_amount.unwrap_or_default(),
569                decimals: value.ui_token_amount.decimals as u32,
570                amount: value.ui_token_amount.amount,
571                ui_amount_string: value.ui_token_amount.ui_amount_string,
572            }),
573            owner: value.owner,
574            program_id: value.program_id,
575        }
576    }
577}
578
579impl From<generated::TokenBalance> for TransactionTokenBalance {
580    fn from(value: generated::TokenBalance) -> Self {
581        let ui_token_amount = value.ui_token_amount.unwrap_or_default();
582        Self {
583            account_index: value.account_index as u8,
584            mint: value.mint,
585            ui_token_amount: UiTokenAmount {
586                ui_amount: if (ui_token_amount.ui_amount - f64::default()).abs() > f64::EPSILON {
587                    Some(ui_token_amount.ui_amount)
588                } else {
589                    None
590                },
591                decimals: ui_token_amount.decimals as u8,
592                amount: ui_token_amount.amount.clone(),
593                ui_amount_string: if !ui_token_amount.ui_amount_string.is_empty() {
594                    ui_token_amount.ui_amount_string
595                } else {
596                    real_number_string_trimmed(
597                        u64::from_str(&ui_token_amount.amount).unwrap_or_default(),
598                        ui_token_amount.decimals as u8,
599                    )
600                },
601            },
602            owner: value.owner,
603            program_id: value.program_id,
604        }
605    }
606}
607
608impl From<Reward> for generated::Reward {
609    fn from(reward: Reward) -> Self {
610        Self {
611            pubkey: reward.pubkey,
612            lamports: reward.lamports,
613            post_balance: reward.post_balance,
614            reward_type: match reward.reward_type {
615                None => generated::RewardType::Unspecified,
616                Some(RewardType::Fee) => generated::RewardType::Fee,
617                Some(RewardType::Rent) => generated::RewardType::Rent,
618                Some(RewardType::Staking) => generated::RewardType::Staking,
619                Some(RewardType::Voting) => generated::RewardType::Voting,
620            } as i32,
621            commission: reward.commission.map(|c| c.to_string()).unwrap_or_default(),
622        }
623    }
624}
625
626impl From<TransactionReturnData> for generated::ReturnData {
627    fn from(value: TransactionReturnData) -> Self {
628        Self {
629            program_id: <Pubkey as AsRef<[u8]>>::as_ref(&value.program_id).into(),
630            data: value.data,
631        }
632    }
633}
634
635impl From<generated::ReturnData> for TransactionReturnData {
636    fn from(value: generated::ReturnData) -> Self {
637        Self {
638            program_id: Pubkey::new(&value.program_id),
639            data: value.data,
640        }
641    }
642}
643
644impl From<generated::MessageHeader> for MessageHeader {
645    fn from(value: generated::MessageHeader) -> Self {
646        Self {
647            num_required_signatures: value.num_required_signatures as u8,
648            num_readonly_signed_accounts: value.num_readonly_signed_accounts as u8,
649            num_readonly_unsigned_accounts: value.num_readonly_unsigned_accounts as u8,
650        }
651    }
652}
653
654impl From<generated::CompiledInstruction> for CompiledInstruction {
655    fn from(value: generated::CompiledInstruction) -> Self {
656        Self {
657            program_id_index: value.program_id_index as u8,
658            accounts: value.accounts,
659            data: value.data,
660        }
661    }
662}
663
664impl From<generated::MessageAddressTableLookup> for MessageAddressTableLookup {
665    fn from(value: generated::MessageAddressTableLookup) -> Self {
666        Self {
667            account_key: Pubkey::new(&value.account_key),
668            writable_indexes: value.writable_indexes,
669            readonly_indexes: value.readonly_indexes,
670        }
671    }
672}
673
674impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
675    type Error = &'static str;
676
677    fn try_from(transaction_error: tx_by_addr::TransactionError) -> Result<Self, Self::Error> {
678        if transaction_error.transaction_error == 8 {
679            if let Some(instruction_error) = transaction_error.instruction_error {
680                if let Some(custom) = instruction_error.custom {
681                    return Ok(TransactionError::InstructionError(
682                        instruction_error.index as u8,
683                        InstructionError::Custom(custom.custom),
684                    ));
685                }
686
687                let ie = match instruction_error.error {
688                    0 => InstructionError::GenericError,
689                    1 => InstructionError::InvalidArgument,
690                    2 => InstructionError::InvalidInstructionData,
691                    3 => InstructionError::InvalidAccountData,
692                    4 => InstructionError::AccountDataTooSmall,
693                    5 => InstructionError::InsufficientFunds,
694                    6 => InstructionError::IncorrectProgramId,
695                    7 => InstructionError::MissingRequiredSignature,
696                    8 => InstructionError::AccountAlreadyInitialized,
697                    9 => InstructionError::UninitializedAccount,
698                    10 => InstructionError::UnbalancedInstruction,
699                    11 => InstructionError::ModifiedProgramId,
700                    12 => InstructionError::ExternalAccountLamportSpend,
701                    13 => InstructionError::ExternalAccountDataModified,
702                    14 => InstructionError::ReadonlyLamportChange,
703                    15 => InstructionError::ReadonlyDataModified,
704                    16 => InstructionError::DuplicateAccountIndex,
705                    17 => InstructionError::ExecutableModified,
706                    18 => InstructionError::RentEpochModified,
707                    19 => InstructionError::NotEnoughAccountKeys,
708                    20 => InstructionError::AccountDataSizeChanged,
709                    21 => InstructionError::AccountNotExecutable,
710                    22 => InstructionError::AccountBorrowFailed,
711                    23 => InstructionError::AccountBorrowOutstanding,
712                    24 => InstructionError::DuplicateAccountOutOfSync,
713                    26 => InstructionError::InvalidError,
714                    27 => InstructionError::ExecutableDataModified,
715                    28 => InstructionError::ExecutableLamportChange,
716                    29 => InstructionError::ExecutableAccountNotRentExempt,
717                    30 => InstructionError::UnsupportedProgramId,
718                    31 => InstructionError::CallDepth,
719                    32 => InstructionError::MissingAccount,
720                    33 => InstructionError::ReentrancyNotAllowed,
721                    34 => InstructionError::MaxSeedLengthExceeded,
722                    35 => InstructionError::InvalidSeeds,
723                    36 => InstructionError::InvalidRealloc,
724                    37 => InstructionError::ComputationalBudgetExceeded,
725                    38 => InstructionError::PrivilegeEscalation,
726                    39 => InstructionError::ProgramEnvironmentSetupFailure,
727                    40 => InstructionError::ProgramFailedToComplete,
728                    41 => InstructionError::ProgramFailedToCompile,
729                    42 => InstructionError::Immutable,
730                    43 => InstructionError::IncorrectAuthority,
731                    44 => InstructionError::BorshIoError(String::new()),
732                    45 => InstructionError::AccountNotRentExempt,
733                    46 => InstructionError::InvalidAccountOwner,
734                    47 => InstructionError::ArithmeticOverflow,
735                    48 => InstructionError::UnsupportedSysvar,
736                    49 => InstructionError::IllegalOwner,
737                    50 => InstructionError::MaxAccountsDataAllocationsExceeded,
738                    51 => InstructionError::MaxAccountsExceeded,
739                    52 => InstructionError::MaxInstructionTraceLengthExceeded,
740                    53 => InstructionError::BuiltinProgramsMustConsumeComputeUnits,
741                    _ => return Err("Invalid InstructionError"),
742                };
743
744                return Ok(TransactionError::InstructionError(
745                    instruction_error.index as u8,
746                    ie,
747                ));
748            }
749        }
750
751        if let Some(transaction_details) = transaction_error.transaction_details {
752            match transaction_error.transaction_error {
753                30 => {
754                    return Ok(TransactionError::DuplicateInstruction(
755                        transaction_details.index as u8,
756                    ));
757                }
758                31 => {
759                    return Ok(TransactionError::InsufficientFundsForRent {
760                        account_index: transaction_details.index as u8,
761                    });
762                }
763                _ => {}
764            }
765        }
766
767        Ok(match transaction_error.transaction_error {
768            0 => TransactionError::AccountInUse,
769            1 => TransactionError::AccountLoadedTwice,
770            2 => TransactionError::AccountNotFound,
771            3 => TransactionError::ProgramAccountNotFound,
772            4 => TransactionError::InsufficientFundsForFee,
773            5 => TransactionError::InvalidAccountForFee,
774            6 => TransactionError::AlreadyProcessed,
775            7 => TransactionError::BlockhashNotFound,
776            9 => TransactionError::CallChainTooDeep,
777            10 => TransactionError::MissingSignatureForFee,
778            11 => TransactionError::InvalidAccountIndex,
779            12 => TransactionError::SignatureFailure,
780            13 => TransactionError::InvalidProgramForExecution,
781            14 => TransactionError::SanitizeFailure,
782            15 => TransactionError::ClusterMaintenance,
783            16 => TransactionError::AccountBorrowOutstanding,
784            17 => TransactionError::WouldExceedMaxBlockCostLimit,
785            18 => TransactionError::UnsupportedVersion,
786            19 => TransactionError::InvalidWritableAccount,
787            20 => TransactionError::WouldExceedMaxAccountCostLimit,
788            21 => TransactionError::WouldExceedAccountDataBlockLimit,
789            22 => TransactionError::TooManyAccountLocks,
790            23 => TransactionError::AddressLookupTableNotFound,
791            24 => TransactionError::InvalidAddressLookupTableOwner,
792            25 => TransactionError::InvalidAddressLookupTableData,
793            26 => TransactionError::InvalidAddressLookupTableIndex,
794            27 => TransactionError::InvalidRentPayingAccount,
795            28 => TransactionError::WouldExceedMaxVoteCostLimit,
796            29 => TransactionError::WouldExceedAccountDataTotalLimit,
797            32 => TransactionError::MaxLoadedAccountsDataSizeExceeded,
798            33 => TransactionError::InvalidLoadedAccountsDataSizeLimit,
799            34 => TransactionError::ResanitizationNeeded,
800            36 => TransactionError::UnbalancedTransaction,
801            _ => return Err("Invalid TransactionError"),
802        })
803    }
804}
805
806impl From<TransactionError> for tx_by_addr::TransactionError {
807    fn from(transaction_error: TransactionError) -> Self {
808        Self {
809            transaction_error: match transaction_error {
810                TransactionError::AccountInUse => tx_by_addr::TransactionErrorType::AccountInUse,
811                TransactionError::AccountLoadedTwice => {
812                    tx_by_addr::TransactionErrorType::AccountLoadedTwice
813                }
814                TransactionError::AccountNotFound => {
815                    tx_by_addr::TransactionErrorType::AccountNotFound
816                }
817                TransactionError::ProgramAccountNotFound => {
818                    tx_by_addr::TransactionErrorType::ProgramAccountNotFound
819                }
820                TransactionError::InsufficientFundsForFee => {
821                    tx_by_addr::TransactionErrorType::InsufficientFundsForFee
822                }
823                TransactionError::InvalidAccountForFee => {
824                    tx_by_addr::TransactionErrorType::InvalidAccountForFee
825                }
826                TransactionError::AlreadyProcessed => {
827                    tx_by_addr::TransactionErrorType::AlreadyProcessed
828                }
829                TransactionError::BlockhashNotFound => {
830                    tx_by_addr::TransactionErrorType::BlockhashNotFound
831                }
832                TransactionError::CallChainTooDeep => {
833                    tx_by_addr::TransactionErrorType::CallChainTooDeep
834                }
835                TransactionError::MissingSignatureForFee => {
836                    tx_by_addr::TransactionErrorType::MissingSignatureForFee
837                }
838                TransactionError::InvalidAccountIndex => {
839                    tx_by_addr::TransactionErrorType::InvalidAccountIndex
840                }
841                TransactionError::SignatureFailure => {
842                    tx_by_addr::TransactionErrorType::SignatureFailure
843                }
844                TransactionError::InvalidProgramForExecution => {
845                    tx_by_addr::TransactionErrorType::InvalidProgramForExecution
846                }
847                TransactionError::SanitizeFailure => {
848                    tx_by_addr::TransactionErrorType::SanitizeFailure
849                }
850                TransactionError::ClusterMaintenance => {
851                    tx_by_addr::TransactionErrorType::ClusterMaintenance
852                }
853                TransactionError::InstructionError(_, _) => {
854                    tx_by_addr::TransactionErrorType::InstructionError
855                }
856                TransactionError::AccountBorrowOutstanding => {
857                    tx_by_addr::TransactionErrorType::AccountBorrowOutstandingTx
858                }
859                TransactionError::WouldExceedMaxBlockCostLimit => {
860                    tx_by_addr::TransactionErrorType::WouldExceedMaxBlockCostLimit
861                }
862                TransactionError::UnsupportedVersion => {
863                    tx_by_addr::TransactionErrorType::UnsupportedVersion
864                }
865                TransactionError::InvalidWritableAccount => {
866                    tx_by_addr::TransactionErrorType::InvalidWritableAccount
867                }
868                TransactionError::WouldExceedMaxAccountCostLimit => {
869                    tx_by_addr::TransactionErrorType::WouldExceedMaxAccountCostLimit
870                }
871                TransactionError::WouldExceedAccountDataBlockLimit => {
872                    tx_by_addr::TransactionErrorType::WouldExceedAccountDataBlockLimit
873                }
874                TransactionError::TooManyAccountLocks => {
875                    tx_by_addr::TransactionErrorType::TooManyAccountLocks
876                }
877                TransactionError::AddressLookupTableNotFound => {
878                    tx_by_addr::TransactionErrorType::AddressLookupTableNotFound
879                }
880                TransactionError::InvalidAddressLookupTableOwner => {
881                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableOwner
882                }
883                TransactionError::InvalidAddressLookupTableData => {
884                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableData
885                }
886                TransactionError::InvalidAddressLookupTableIndex => {
887                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableIndex
888                }
889                TransactionError::InvalidRentPayingAccount => {
890                    tx_by_addr::TransactionErrorType::InvalidRentPayingAccount
891                }
892                TransactionError::WouldExceedMaxVoteCostLimit => {
893                    tx_by_addr::TransactionErrorType::WouldExceedMaxVoteCostLimit
894                }
895                TransactionError::WouldExceedAccountDataTotalLimit => {
896                    tx_by_addr::TransactionErrorType::WouldExceedAccountDataTotalLimit
897                }
898                TransactionError::DuplicateInstruction(_) => {
899                    tx_by_addr::TransactionErrorType::DuplicateInstruction
900                }
901                TransactionError::InsufficientFundsForRent { .. } => {
902                    tx_by_addr::TransactionErrorType::InsufficientFundsForRent
903                }
904                TransactionError::MaxLoadedAccountsDataSizeExceeded => {
905                    tx_by_addr::TransactionErrorType::MaxLoadedAccountsDataSizeExceeded
906                }
907                TransactionError::InvalidLoadedAccountsDataSizeLimit => {
908                    tx_by_addr::TransactionErrorType::InvalidLoadedAccountsDataSizeLimit
909                }
910                TransactionError::ResanitizationNeeded => {
911                    tx_by_addr::TransactionErrorType::ResanitizationNeeded
912                }
913                TransactionError::UnbalancedTransaction => {
914                    tx_by_addr::TransactionErrorType::UnbalancedTransaction
915                }
916            } as i32,
917            instruction_error: match transaction_error {
918                TransactionError::InstructionError(index, ref instruction_error) => {
919                    Some(tx_by_addr::InstructionError {
920                        index: index as u32,
921                        error: match instruction_error {
922                            InstructionError::GenericError => {
923                                tx_by_addr::InstructionErrorType::GenericError
924                            }
925                            InstructionError::InvalidArgument => {
926                                tx_by_addr::InstructionErrorType::InvalidArgument
927                            }
928                            InstructionError::InvalidInstructionData => {
929                                tx_by_addr::InstructionErrorType::InvalidInstructionData
930                            }
931                            InstructionError::InvalidAccountData => {
932                                tx_by_addr::InstructionErrorType::InvalidAccountData
933                            }
934                            InstructionError::AccountDataTooSmall => {
935                                tx_by_addr::InstructionErrorType::AccountDataTooSmall
936                            }
937                            InstructionError::InsufficientFunds => {
938                                tx_by_addr::InstructionErrorType::InsufficientFunds
939                            }
940                            InstructionError::IncorrectProgramId => {
941                                tx_by_addr::InstructionErrorType::IncorrectProgramId
942                            }
943                            InstructionError::MissingRequiredSignature => {
944                                tx_by_addr::InstructionErrorType::MissingRequiredSignature
945                            }
946                            InstructionError::AccountAlreadyInitialized => {
947                                tx_by_addr::InstructionErrorType::AccountAlreadyInitialized
948                            }
949                            InstructionError::UninitializedAccount => {
950                                tx_by_addr::InstructionErrorType::UninitializedAccount
951                            }
952                            InstructionError::UnbalancedInstruction => {
953                                tx_by_addr::InstructionErrorType::UnbalancedInstruction
954                            }
955                            InstructionError::ModifiedProgramId => {
956                                tx_by_addr::InstructionErrorType::ModifiedProgramId
957                            }
958                            InstructionError::ExternalAccountLamportSpend => {
959                                tx_by_addr::InstructionErrorType::ExternalAccountLamportSpend
960                            }
961                            InstructionError::ExternalAccountDataModified => {
962                                tx_by_addr::InstructionErrorType::ExternalAccountDataModified
963                            }
964                            InstructionError::ReadonlyLamportChange => {
965                                tx_by_addr::InstructionErrorType::ReadonlyLamportChange
966                            }
967                            InstructionError::ReadonlyDataModified => {
968                                tx_by_addr::InstructionErrorType::ReadonlyDataModified
969                            }
970                            InstructionError::DuplicateAccountIndex => {
971                                tx_by_addr::InstructionErrorType::DuplicateAccountIndex
972                            }
973                            InstructionError::ExecutableModified => {
974                                tx_by_addr::InstructionErrorType::ExecutableModified
975                            }
976                            InstructionError::RentEpochModified => {
977                                tx_by_addr::InstructionErrorType::RentEpochModified
978                            }
979                            InstructionError::NotEnoughAccountKeys => {
980                                tx_by_addr::InstructionErrorType::NotEnoughAccountKeys
981                            }
982                            InstructionError::AccountDataSizeChanged => {
983                                tx_by_addr::InstructionErrorType::AccountDataSizeChanged
984                            }
985                            InstructionError::AccountNotExecutable => {
986                                tx_by_addr::InstructionErrorType::AccountNotExecutable
987                            }
988                            InstructionError::AccountBorrowFailed => {
989                                tx_by_addr::InstructionErrorType::AccountBorrowFailed
990                            }
991                            InstructionError::AccountBorrowOutstanding => {
992                                tx_by_addr::InstructionErrorType::AccountBorrowOutstanding
993                            }
994                            InstructionError::DuplicateAccountOutOfSync => {
995                                tx_by_addr::InstructionErrorType::DuplicateAccountOutOfSync
996                            }
997                            InstructionError::Custom(_) => tx_by_addr::InstructionErrorType::Custom,
998                            InstructionError::InvalidError => {
999                                tx_by_addr::InstructionErrorType::InvalidError
1000                            }
1001                            InstructionError::ExecutableDataModified => {
1002                                tx_by_addr::InstructionErrorType::ExecutableDataModified
1003                            }
1004                            InstructionError::ExecutableLamportChange => {
1005                                tx_by_addr::InstructionErrorType::ExecutableLamportChange
1006                            }
1007                            InstructionError::ExecutableAccountNotRentExempt => {
1008                                tx_by_addr::InstructionErrorType::ExecutableAccountNotRentExempt
1009                            }
1010                            InstructionError::UnsupportedProgramId => {
1011                                tx_by_addr::InstructionErrorType::UnsupportedProgramId
1012                            }
1013                            InstructionError::CallDepth => {
1014                                tx_by_addr::InstructionErrorType::CallDepth
1015                            }
1016                            InstructionError::MissingAccount => {
1017                                tx_by_addr::InstructionErrorType::MissingAccount
1018                            }
1019                            InstructionError::ReentrancyNotAllowed => {
1020                                tx_by_addr::InstructionErrorType::ReentrancyNotAllowed
1021                            }
1022                            InstructionError::MaxSeedLengthExceeded => {
1023                                tx_by_addr::InstructionErrorType::MaxSeedLengthExceeded
1024                            }
1025                            InstructionError::InvalidSeeds => {
1026                                tx_by_addr::InstructionErrorType::InvalidSeeds
1027                            }
1028                            InstructionError::InvalidRealloc => {
1029                                tx_by_addr::InstructionErrorType::InvalidRealloc
1030                            }
1031                            InstructionError::ComputationalBudgetExceeded => {
1032                                tx_by_addr::InstructionErrorType::ComputationalBudgetExceeded
1033                            }
1034                            InstructionError::PrivilegeEscalation => {
1035                                tx_by_addr::InstructionErrorType::PrivilegeEscalation
1036                            }
1037                            InstructionError::ProgramEnvironmentSetupFailure => {
1038                                tx_by_addr::InstructionErrorType::ProgramEnvironmentSetupFailure
1039                            }
1040                            InstructionError::ProgramFailedToComplete => {
1041                                tx_by_addr::InstructionErrorType::ProgramFailedToComplete
1042                            }
1043                            InstructionError::ProgramFailedToCompile => {
1044                                tx_by_addr::InstructionErrorType::ProgramFailedToCompile
1045                            }
1046                            InstructionError::Immutable => {
1047                                tx_by_addr::InstructionErrorType::Immutable
1048                            }
1049                            InstructionError::IncorrectAuthority => {
1050                                tx_by_addr::InstructionErrorType::IncorrectAuthority
1051                            }
1052                            InstructionError::BorshIoError(_) => {
1053                                tx_by_addr::InstructionErrorType::BorshIoError
1054                            }
1055                            InstructionError::AccountNotRentExempt => {
1056                                tx_by_addr::InstructionErrorType::AccountNotRentExempt
1057                            }
1058                            InstructionError::InvalidAccountOwner => {
1059                                tx_by_addr::InstructionErrorType::InvalidAccountOwner
1060                            }
1061                            InstructionError::ArithmeticOverflow => {
1062                                tx_by_addr::InstructionErrorType::ArithmeticOverflow
1063                            }
1064                            InstructionError::UnsupportedSysvar => {
1065                                tx_by_addr::InstructionErrorType::UnsupportedSysvar
1066                            }
1067                            InstructionError::IllegalOwner => {
1068                                tx_by_addr::InstructionErrorType::IllegalOwner
1069                            }
1070                            InstructionError::MaxAccountsDataAllocationsExceeded => {
1071                                tx_by_addr::InstructionErrorType::MaxAccountsDataAllocationsExceeded
1072                            }
1073                            InstructionError::MaxAccountsExceeded => {
1074                                tx_by_addr::InstructionErrorType::MaxAccountsExceeded
1075                            }
1076                            InstructionError::MaxInstructionTraceLengthExceeded => {
1077                                tx_by_addr::InstructionErrorType::MaxInstructionTraceLengthExceeded
1078                            }
1079                            InstructionError::BuiltinProgramsMustConsumeComputeUnits => {
1080                                tx_by_addr::InstructionErrorType::BuiltinProgramsMustConsumeComputeUnits
1081                            }
1082                        } as i32,
1083                        custom: match instruction_error {
1084                            InstructionError::Custom(custom) => {
1085                                Some(tx_by_addr::CustomError { custom: *custom })
1086                            }
1087                            _ => None,
1088                        },
1089                    })
1090                }
1091                _ => None,
1092            },
1093            transaction_details: match transaction_error {
1094                TransactionError::DuplicateInstruction(index) => {
1095                    Some(tx_by_addr::TransactionDetails {
1096                        index: index as u32,
1097                    })
1098                }
1099                TransactionError::InsufficientFundsForRent { account_index } => {
1100                    Some(tx_by_addr::TransactionDetails {
1101                        index: account_index as u32,
1102                    })
1103                }
1104                _ => None,
1105            },
1106        }
1107    }
1108}
1109
1110impl From<TransactionByAddrInfo> for tx_by_addr::TransactionByAddrInfo {
1111    fn from(by_addr: TransactionByAddrInfo) -> Self {
1112        let TransactionByAddrInfo {
1113            signature,
1114            err,
1115            index,
1116            memo,
1117            block_time,
1118        } = by_addr;
1119
1120        Self {
1121            signature: <Signature as AsRef<[u8]>>::as_ref(&signature).into(),
1122            err: err.map(|e| e.into()),
1123            index,
1124            memo: memo.map(|memo| tx_by_addr::Memo { memo }),
1125            block_time: block_time.map(|timestamp| tx_by_addr::UnixTimestamp { timestamp }),
1126        }
1127    }
1128}