Skip to main content

solana_storage_proto/
convert.rs

1use {
2    crate::{StoredExtendedRewards, StoredTransactionError, StoredTransactionStatusMeta},
3    solana_account_decoder::parse_token::{UiTokenAmount, real_number_string_trimmed},
4    solana_hash::{HASH_BYTES, Hash},
5    solana_instruction::error::InstructionError,
6    solana_message::{
7        MessageHeader, VersionedMessage,
8        compiled_instruction::CompiledInstruction,
9        legacy::Message as LegacyMessage,
10        v0::{self, LoadedAddresses, MessageAddressTableLookup},
11        v1,
12    },
13    solana_pubkey::Pubkey,
14    solana_signature::Signature,
15    solana_transaction::{Transaction, versioned::VersionedTransaction},
16    solana_transaction_context::transaction::TransactionReturnData,
17    solana_transaction_error::TransactionError,
18    solana_transaction_status::{
19        ConfirmedBlock, EntrySummary, InnerInstruction, InnerInstructions, Reward, RewardType,
20        RewardsAndNumPartitions, TransactionByAddrInfo, TransactionStatusMeta,
21        TransactionTokenBalance, TransactionWithStatusMeta, VersionedConfirmedBlock,
22        VersionedTransactionWithStatusMeta,
23    },
24    std::{
25        convert::{TryFrom, TryInto},
26        str::FromStr,
27    },
28    wincode::ReadError,
29};
30
31pub mod generated {
32    include!(concat!(
33        env!("OUT_DIR"),
34        "/solana.storage.confirmed_block.rs"
35    ));
36}
37
38pub mod tx_by_addr {
39    include!(concat!(
40        env!("OUT_DIR"),
41        "/solana.storage.transaction_by_addr.rs"
42    ));
43}
44
45pub mod entries {
46    include!(concat!(env!("OUT_DIR"), "/solana.storage.entries.rs"));
47}
48
49#[derive(Debug, thiserror::Error)]
50#[error("failed to decode {bytes:?}: {source}")]
51pub struct DecodeError {
52    pub bytes: Vec<u8>,
53    #[source]
54    pub source: ReadError,
55}
56
57impl From<Vec<Reward>> for generated::Rewards {
58    fn from(rewards: Vec<Reward>) -> Self {
59        Self {
60            rewards: rewards.into_iter().map(|r| r.into()).collect(),
61            num_partitions: None,
62        }
63    }
64}
65
66impl From<RewardsAndNumPartitions> for generated::Rewards {
67    fn from(input: RewardsAndNumPartitions) -> Self {
68        Self {
69            rewards: input.rewards.into_iter().map(|r| r.into()).collect(),
70            num_partitions: input.num_partitions.map(|n| n.into()),
71        }
72    }
73}
74
75impl From<generated::Rewards> for Vec<Reward> {
76    fn from(rewards: generated::Rewards) -> Self {
77        rewards.rewards.into_iter().map(|r| r.into()).collect()
78    }
79}
80
81impl From<generated::Rewards> for RewardsAndNumPartitions {
82    fn from(rewards: generated::Rewards) -> Self {
83        Self {
84            rewards: rewards.rewards.into_iter().map(|r| r.into()).collect(),
85            num_partitions: rewards
86                .num_partitions
87                .map(|generated::NumPartitions { num_partitions }| num_partitions),
88        }
89    }
90}
91
92impl From<StoredExtendedRewards> for generated::Rewards {
93    fn from(rewards: StoredExtendedRewards) -> Self {
94        Self {
95            rewards: rewards
96                .into_iter()
97                .map(|r| {
98                    let r: Reward = r.into();
99                    r.into()
100                })
101                .collect(),
102            num_partitions: None,
103        }
104    }
105}
106
107impl From<generated::Rewards> for StoredExtendedRewards {
108    fn from(rewards: generated::Rewards) -> Self {
109        rewards
110            .rewards
111            .into_iter()
112            .map(|r| {
113                let r: Reward = r.into();
114                r.into()
115            })
116            .collect()
117    }
118}
119
120impl From<Reward> for generated::Reward {
121    fn from(reward: Reward) -> Self {
122        Self {
123            pubkey: reward.pubkey,
124            lamports: reward.lamports,
125            post_balance: reward.post_balance,
126            reward_type: match reward.reward_type {
127                None => generated::RewardType::Unspecified,
128                Some(RewardType::Fee) => generated::RewardType::Fee,
129                Some(RewardType::Rent) => generated::RewardType::Rent,
130                Some(RewardType::Staking) => generated::RewardType::Staking,
131                Some(RewardType::Voting) => generated::RewardType::Voting,
132                Some(RewardType::DeactivatedStake) => generated::RewardType::DeactivatedStake,
133            } as i32,
134            commission: reward.commission.map(|c| c.to_string()).unwrap_or_default(),
135            commission_bps: reward
136                .commission_bps
137                .map(|bps| bps.to_string())
138                .unwrap_or_default(),
139        }
140    }
141}
142
143impl From<generated::Reward> for Reward {
144    fn from(reward: generated::Reward) -> Self {
145        Self {
146            pubkey: reward.pubkey,
147            lamports: reward.lamports,
148            post_balance: reward.post_balance,
149            reward_type: match reward.reward_type {
150                0 => None,
151                1 => Some(RewardType::Fee),
152                2 => Some(RewardType::Rent),
153                3 => Some(RewardType::Staking),
154                4 => Some(RewardType::Voting),
155                5 => Some(RewardType::DeactivatedStake),
156                _ => None,
157            },
158            commission: reward.commission.parse::<u8>().ok(),
159            commission_bps: reward.commission_bps.parse::<u16>().ok(),
160        }
161    }
162}
163
164impl From<u64> for generated::NumPartitions {
165    fn from(num_partitions: u64) -> Self {
166        Self { num_partitions }
167    }
168}
169
170impl From<VersionedConfirmedBlock> for generated::ConfirmedBlock {
171    fn from(confirmed_block: VersionedConfirmedBlock) -> Self {
172        let VersionedConfirmedBlock {
173            previous_blockhash,
174            blockhash,
175            parent_slot,
176            transactions,
177            rewards,
178            num_partitions,
179            block_time,
180            block_height,
181        } = confirmed_block;
182
183        Self {
184            previous_blockhash,
185            blockhash,
186            parent_slot,
187            transactions: transactions.into_iter().map(|tx| tx.into()).collect(),
188            rewards: rewards.into_iter().map(|r| r.into()).collect(),
189            num_partitions: num_partitions.map(Into::into),
190            block_time: block_time.map(|timestamp| generated::UnixTimestamp { timestamp }),
191            block_height: block_height.map(|block_height| generated::BlockHeight { block_height }),
192        }
193    }
194}
195
196impl TryFrom<generated::ConfirmedBlock> for ConfirmedBlock {
197    type Error = DecodeError;
198    fn try_from(
199        confirmed_block: generated::ConfirmedBlock,
200    ) -> std::result::Result<Self, Self::Error> {
201        let generated::ConfirmedBlock {
202            previous_blockhash,
203            blockhash,
204            parent_slot,
205            transactions,
206            rewards,
207            num_partitions,
208            block_time,
209            block_height,
210        } = confirmed_block;
211
212        Ok(Self {
213            previous_blockhash,
214            blockhash,
215            parent_slot,
216            transactions: transactions
217                .into_iter()
218                .map(|tx| tx.try_into())
219                .collect::<std::result::Result<Vec<_>, Self::Error>>()?,
220            rewards: rewards.into_iter().map(|r| r.into()).collect(),
221            num_partitions: num_partitions
222                .map(|generated::NumPartitions { num_partitions }| num_partitions),
223            block_time: block_time.map(|generated::UnixTimestamp { timestamp }| timestamp),
224            block_height: block_height.map(|generated::BlockHeight { block_height }| block_height),
225        })
226    }
227}
228
229impl From<TransactionWithStatusMeta> for generated::ConfirmedTransaction {
230    fn from(tx_with_meta: TransactionWithStatusMeta) -> Self {
231        match tx_with_meta {
232            TransactionWithStatusMeta::MissingMetadata(transaction) => Self {
233                transaction: Some(generated::Transaction::from(transaction)),
234                meta: None,
235            },
236            TransactionWithStatusMeta::Complete(tx_with_meta) => Self::from(tx_with_meta),
237        }
238    }
239}
240
241impl From<VersionedTransactionWithStatusMeta> for generated::ConfirmedTransaction {
242    fn from(value: VersionedTransactionWithStatusMeta) -> Self {
243        Self {
244            transaction: Some(value.transaction.into()),
245            meta: Some(value.meta.into()),
246        }
247    }
248}
249
250impl TryFrom<generated::ConfirmedTransaction> for TransactionWithStatusMeta {
251    type Error = DecodeError;
252    fn try_from(value: generated::ConfirmedTransaction) -> std::result::Result<Self, Self::Error> {
253        let meta = value.meta.map(|meta| meta.try_into()).transpose()?;
254        let transaction = value.transaction.expect("transaction is required").into();
255        Ok(match meta {
256            Some(meta) => Self::Complete(VersionedTransactionWithStatusMeta { transaction, meta }),
257            None => Self::MissingMetadata(
258                transaction
259                    .into_legacy_transaction()
260                    .expect("meta is required for versioned transactions"),
261            ),
262        })
263    }
264}
265
266impl From<Transaction> for generated::Transaction {
267    fn from(value: Transaction) -> Self {
268        Self {
269            signatures: value
270                .signatures
271                .into_iter()
272                .map(|signature| <Signature as AsRef<[u8]>>::as_ref(&signature).into())
273                .collect(),
274            message: Some(value.message.into()),
275        }
276    }
277}
278
279impl From<VersionedTransaction> for generated::Transaction {
280    fn from(value: VersionedTransaction) -> Self {
281        Self {
282            signatures: value
283                .signatures
284                .into_iter()
285                .map(|signature| <Signature as AsRef<[u8]>>::as_ref(&signature).into())
286                .collect(),
287            message: Some(value.message.into()),
288        }
289    }
290}
291
292impl From<generated::Transaction> for VersionedTransaction {
293    fn from(value: generated::Transaction) -> Self {
294        Self {
295            signatures: value
296                .signatures
297                .into_iter()
298                .map(Signature::try_from)
299                .collect::<Result<_, _>>()
300                .unwrap(),
301            message: value.message.expect("message is required").into(),
302        }
303    }
304}
305
306impl From<TransactionError> for generated::TransactionError {
307    fn from(value: TransactionError) -> Self {
308        let stored_error = StoredTransactionError::from(value).0;
309        Self { err: stored_error }
310    }
311}
312
313impl From<generated::TransactionError> for TransactionError {
314    fn from(value: generated::TransactionError) -> Self {
315        let stored_error = StoredTransactionError(value.err);
316        stored_error.into()
317    }
318}
319
320impl From<LegacyMessage> for generated::Message {
321    fn from(message: LegacyMessage) -> Self {
322        Self {
323            header: Some(message.header.into()),
324            account_keys: message
325                .account_keys
326                .iter()
327                .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(key).into())
328                .collect(),
329            recent_blockhash: message.recent_blockhash.to_bytes().into(),
330            instructions: message
331                .instructions
332                .into_iter()
333                .map(|ix| ix.into())
334                .collect(),
335            versioned: false,
336            address_table_lookups: vec![],
337            config: None,
338        }
339    }
340}
341
342impl From<v0::Message> for generated::Message {
343    fn from(message: v0::Message) -> Self {
344        Self {
345            header: Some(message.header.into()),
346            account_keys: message
347                .account_keys
348                .iter()
349                .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(key).into())
350                .collect(),
351            recent_blockhash: message.recent_blockhash.to_bytes().into(),
352            instructions: message
353                .instructions
354                .into_iter()
355                .map(|ix| ix.into())
356                .collect(),
357            versioned: true,
358            address_table_lookups: message
359                .address_table_lookups
360                .into_iter()
361                .map(|lookup| lookup.into())
362                .collect(),
363            config: None,
364        }
365    }
366}
367
368impl From<v1::Message> for generated::Message {
369    fn from(message: v1::Message) -> Self {
370        Self {
371            header: Some(message.header.into()),
372            account_keys: message
373                .account_keys
374                .iter()
375                .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(key).into())
376                .collect(),
377            recent_blockhash: message.lifetime_specifier.to_bytes().into(),
378            instructions: message
379                .instructions
380                .into_iter()
381                .map(|ix| ix.into())
382                .collect(),
383            versioned: true,
384            address_table_lookups: vec![],
385            config: Some(generated::TransactionConfig {
386                priority_fee: message.config.priority_fee,
387                compute_unit_limit: message.config.compute_unit_limit,
388                loaded_accounts_data_size_limit: message.config.loaded_accounts_data_size_limit,
389                heap_size: message.config.heap_size,
390            }),
391        }
392    }
393}
394
395impl From<VersionedMessage> for generated::Message {
396    fn from(message: VersionedMessage) -> Self {
397        match message {
398            VersionedMessage::Legacy(message) => Self::from(message),
399            VersionedMessage::V0(message) => Self::from(message),
400            VersionedMessage::V1(message) => Self::from(message),
401        }
402    }
403}
404
405impl From<generated::Message> for VersionedMessage {
406    fn from(value: generated::Message) -> Self {
407        let header = value.header.expect("header is required").into();
408        let account_keys = value
409            .account_keys
410            .into_iter()
411            .map(|key| Pubkey::try_from(key).unwrap())
412            .collect();
413        let recent_blockhash = <[u8; HASH_BYTES]>::try_from(value.recent_blockhash)
414            .map(Hash::new_from_array)
415            .unwrap();
416        let instructions = value.instructions.into_iter().map(|ix| ix.into()).collect();
417
418        // `config` is written only for V1 messages, whose lifetime specifier travels in
419        // `recent_blockhash` and which have no address table lookups. It has to be checked before
420        // `versioned`, which is true for V0 *and* V1 and so cannot tell them apart on its own.
421        if let Some(config) = value.config {
422            return Self::V1(v1::Message {
423                header,
424                config: v1::TransactionConfig {
425                    priority_fee: config.priority_fee,
426                    compute_unit_limit: config.compute_unit_limit,
427                    loaded_accounts_data_size_limit: config.loaded_accounts_data_size_limit,
428                    heap_size: config.heap_size,
429                },
430                lifetime_specifier: recent_blockhash,
431                account_keys,
432                instructions,
433            });
434        }
435
436        let address_table_lookups = value
437            .address_table_lookups
438            .into_iter()
439            .map(|lookup| lookup.into())
440            .collect();
441
442        if !value.versioned {
443            Self::Legacy(LegacyMessage {
444                header,
445                account_keys,
446                recent_blockhash,
447                instructions,
448            })
449        } else {
450            Self::V0(v0::Message {
451                header,
452                account_keys,
453                recent_blockhash,
454                instructions,
455                address_table_lookups,
456            })
457        }
458    }
459}
460
461impl From<MessageHeader> for generated::MessageHeader {
462    fn from(value: MessageHeader) -> Self {
463        Self {
464            num_required_signatures: value.num_required_signatures as u32,
465            num_readonly_signed_accounts: value.num_readonly_signed_accounts as u32,
466            num_readonly_unsigned_accounts: value.num_readonly_unsigned_accounts as u32,
467        }
468    }
469}
470
471impl From<generated::MessageHeader> for MessageHeader {
472    fn from(value: generated::MessageHeader) -> Self {
473        Self {
474            num_required_signatures: value.num_required_signatures as u8,
475            num_readonly_signed_accounts: value.num_readonly_signed_accounts as u8,
476            num_readonly_unsigned_accounts: value.num_readonly_unsigned_accounts as u8,
477        }
478    }
479}
480
481impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
482    fn from(value: TransactionStatusMeta) -> Self {
483        let TransactionStatusMeta {
484            status,
485            fee,
486            pre_balances,
487            post_balances,
488            inner_instructions,
489            log_messages,
490            pre_token_balances,
491            post_token_balances,
492            rewards,
493            loaded_addresses,
494            return_data,
495            compute_units_consumed,
496            cost_units,
497        } = value;
498        let err = match status {
499            Ok(()) => None,
500            Err(err) => Some(generated::TransactionError {
501                err: wincode::serialize(&err).expect("transaction error to serialize to bytes"),
502            }),
503        };
504        let inner_instructions_none = inner_instructions.is_none();
505        let inner_instructions = inner_instructions
506            .unwrap_or_default()
507            .into_iter()
508            .map(|ii| ii.into())
509            .collect();
510        let log_messages_none = log_messages.is_none();
511        let log_messages = log_messages.unwrap_or_default();
512        let pre_token_balances = pre_token_balances
513            .unwrap_or_default()
514            .into_iter()
515            .map(|balance| balance.into())
516            .collect();
517        let post_token_balances = post_token_balances
518            .unwrap_or_default()
519            .into_iter()
520            .map(|balance| balance.into())
521            .collect();
522        let rewards = rewards
523            .unwrap_or_default()
524            .into_iter()
525            .map(|reward| reward.into())
526            .collect();
527        let loaded_writable_addresses = loaded_addresses
528            .writable
529            .into_iter()
530            .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
531            .collect();
532        let loaded_readonly_addresses = loaded_addresses
533            .readonly
534            .into_iter()
535            .map(|key| <Pubkey as AsRef<[u8]>>::as_ref(&key).into())
536            .collect();
537        let return_data_none = return_data.is_none();
538        let return_data = return_data.map(|return_data| return_data.into());
539
540        Self {
541            err,
542            fee,
543            pre_balances,
544            post_balances,
545            inner_instructions,
546            inner_instructions_none,
547            log_messages,
548            log_messages_none,
549            pre_token_balances,
550            post_token_balances,
551            rewards,
552            loaded_writable_addresses,
553            loaded_readonly_addresses,
554            return_data,
555            return_data_none,
556            compute_units_consumed,
557            cost_units,
558        }
559    }
560}
561
562impl From<StoredTransactionStatusMeta> for generated::TransactionStatusMeta {
563    fn from(meta: StoredTransactionStatusMeta) -> Self {
564        let meta: TransactionStatusMeta = meta.into();
565        meta.into()
566    }
567}
568
569impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
570    type Error = DecodeError;
571
572    fn try_from(value: generated::TransactionStatusMeta) -> std::result::Result<Self, Self::Error> {
573        let generated::TransactionStatusMeta {
574            err,
575            fee,
576            pre_balances,
577            post_balances,
578            inner_instructions,
579            inner_instructions_none,
580            log_messages,
581            log_messages_none,
582            pre_token_balances,
583            post_token_balances,
584            rewards,
585            loaded_writable_addresses,
586            loaded_readonly_addresses,
587            return_data,
588            return_data_none,
589            compute_units_consumed,
590            cost_units,
591        } = value;
592        let status = match err {
593            None => Ok(()),
594            Some(tx_error) => {
595                let tx_error =
596                    wincode::deserialize(&tx_error.err).map_err(|source| DecodeError {
597                        bytes: tx_error.err,
598                        source,
599                    })?;
600                Err(tx_error)
601            }
602        };
603        let inner_instructions = if inner_instructions_none {
604            None
605        } else {
606            Some(
607                inner_instructions
608                    .into_iter()
609                    .map(|inner| inner.into())
610                    .collect(),
611            )
612        };
613        let log_messages = if log_messages_none {
614            None
615        } else {
616            Some(log_messages)
617        };
618        let pre_token_balances = Some(
619            pre_token_balances
620                .into_iter()
621                .map(|balance| balance.into())
622                .collect(),
623        );
624        let post_token_balances = Some(
625            post_token_balances
626                .into_iter()
627                .map(|balance| balance.into())
628                .collect(),
629        );
630        let rewards = Some(rewards.into_iter().map(|reward| reward.into()).collect());
631        let loaded_addresses = LoadedAddresses {
632            writable: loaded_writable_addresses
633                .into_iter()
634                .map(Pubkey::try_from)
635                .collect::<Result<_, _>>()
636                .map_err(|bytes| DecodeError {
637                    bytes,
638                    source: ReadError::Custom("Invalid writable address"),
639                })?,
640            readonly: loaded_readonly_addresses
641                .into_iter()
642                .map(Pubkey::try_from)
643                .collect::<Result<_, _>>()
644                .map_err(|bytes| DecodeError {
645                    bytes,
646                    source: ReadError::Custom("Invalid readonly address"),
647                })?,
648        };
649        let return_data = if return_data_none {
650            None
651        } else {
652            return_data.map(|return_data| return_data.into())
653        };
654        Ok(Self {
655            status,
656            fee,
657            pre_balances,
658            post_balances,
659            inner_instructions,
660            log_messages,
661            pre_token_balances,
662            post_token_balances,
663            rewards,
664            loaded_addresses,
665            return_data,
666            compute_units_consumed,
667            cost_units,
668        })
669    }
670}
671
672impl From<InnerInstructions> for generated::InnerInstructions {
673    fn from(value: InnerInstructions) -> Self {
674        Self {
675            index: value.index as u32,
676            instructions: value.instructions.into_iter().map(|i| i.into()).collect(),
677        }
678    }
679}
680
681impl From<generated::InnerInstructions> for InnerInstructions {
682    fn from(value: generated::InnerInstructions) -> Self {
683        Self {
684            index: value.index as u8,
685            instructions: value.instructions.into_iter().map(|i| i.into()).collect(),
686        }
687    }
688}
689
690impl From<TransactionTokenBalance> for generated::TokenBalance {
691    fn from(value: TransactionTokenBalance) -> Self {
692        Self {
693            account_index: value.account_index as u32,
694            mint: value.mint,
695            ui_token_amount: Some(generated::UiTokenAmount {
696                ui_amount: value.ui_token_amount.ui_amount.unwrap_or_default(),
697                decimals: value.ui_token_amount.decimals as u32,
698                amount: value.ui_token_amount.amount,
699                ui_amount_string: value.ui_token_amount.ui_amount_string,
700            }),
701            owner: value.owner,
702            program_id: value.program_id,
703        }
704    }
705}
706
707impl From<generated::TokenBalance> for TransactionTokenBalance {
708    fn from(value: generated::TokenBalance) -> Self {
709        let ui_token_amount = value.ui_token_amount.unwrap_or_default();
710        Self {
711            account_index: value.account_index as u8,
712            mint: value.mint,
713            ui_token_amount: UiTokenAmount {
714                ui_amount: if (ui_token_amount.ui_amount - f64::default()).abs() > f64::EPSILON {
715                    Some(ui_token_amount.ui_amount)
716                } else {
717                    None
718                },
719                decimals: ui_token_amount.decimals as u8,
720                amount: ui_token_amount.amount.clone(),
721                ui_amount_string: if !ui_token_amount.ui_amount_string.is_empty() {
722                    ui_token_amount.ui_amount_string
723                } else {
724                    real_number_string_trimmed(
725                        u64::from_str(&ui_token_amount.amount).unwrap_or_default(),
726                        ui_token_amount.decimals as u8,
727                    )
728                },
729            },
730            owner: value.owner,
731            program_id: value.program_id,
732        }
733    }
734}
735
736impl From<MessageAddressTableLookup> for generated::MessageAddressTableLookup {
737    fn from(lookup: MessageAddressTableLookup) -> Self {
738        Self {
739            account_key: <Pubkey as AsRef<[u8]>>::as_ref(&lookup.account_key).into(),
740            writable_indexes: lookup.writable_indexes,
741            readonly_indexes: lookup.readonly_indexes,
742        }
743    }
744}
745
746impl From<generated::MessageAddressTableLookup> for MessageAddressTableLookup {
747    fn from(value: generated::MessageAddressTableLookup) -> Self {
748        Self {
749            account_key: Pubkey::try_from(value.account_key).unwrap(),
750            writable_indexes: value.writable_indexes,
751            readonly_indexes: value.readonly_indexes,
752        }
753    }
754}
755
756impl From<TransactionReturnData> for generated::ReturnData {
757    fn from(value: TransactionReturnData) -> Self {
758        Self {
759            program_id: <Pubkey as AsRef<[u8]>>::as_ref(&value.program_id).into(),
760            data: value.data,
761        }
762    }
763}
764
765impl From<generated::ReturnData> for TransactionReturnData {
766    fn from(value: generated::ReturnData) -> Self {
767        Self {
768            program_id: Pubkey::try_from(value.program_id).unwrap(),
769            data: value.data,
770        }
771    }
772}
773
774impl From<CompiledInstruction> for generated::CompiledInstruction {
775    fn from(value: CompiledInstruction) -> Self {
776        Self {
777            program_id_index: value.program_id_index as u32,
778            accounts: value.accounts,
779            data: value.data,
780        }
781    }
782}
783
784impl From<generated::CompiledInstruction> for CompiledInstruction {
785    fn from(value: generated::CompiledInstruction) -> Self {
786        Self {
787            program_id_index: value.program_id_index as u8,
788            accounts: value.accounts,
789            data: value.data,
790        }
791    }
792}
793
794impl From<InnerInstruction> for generated::InnerInstruction {
795    fn from(value: InnerInstruction) -> Self {
796        Self {
797            program_id_index: value.instruction.program_id_index as u32,
798            accounts: value.instruction.accounts,
799            data: value.instruction.data,
800            stack_height: value.stack_height,
801        }
802    }
803}
804
805impl From<generated::InnerInstruction> for InnerInstruction {
806    fn from(value: generated::InnerInstruction) -> Self {
807        Self {
808            instruction: CompiledInstruction {
809                program_id_index: value.program_id_index as u8,
810                accounts: value.accounts,
811                data: value.data,
812            },
813            stack_height: value.stack_height,
814        }
815    }
816}
817
818impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
819    type Error = &'static str;
820
821    fn try_from(transaction_error: tx_by_addr::TransactionError) -> Result<Self, Self::Error> {
822        if transaction_error.transaction_error == 8
823            && let Some(instruction_error) = transaction_error.instruction_error
824        {
825            if let Some(custom) = instruction_error.custom {
826                return Ok(TransactionError::InstructionError(
827                    instruction_error.index as u8,
828                    InstructionError::Custom(custom.custom),
829                ));
830            }
831
832            let ie = match instruction_error.error {
833                0 => InstructionError::GenericError,
834                1 => InstructionError::InvalidArgument,
835                2 => InstructionError::InvalidInstructionData,
836                3 => InstructionError::InvalidAccountData,
837                4 => InstructionError::AccountDataTooSmall,
838                5 => InstructionError::InsufficientFunds,
839                6 => InstructionError::IncorrectProgramId,
840                7 => InstructionError::MissingRequiredSignature,
841                8 => InstructionError::AccountAlreadyInitialized,
842                9 => InstructionError::UninitializedAccount,
843                10 => InstructionError::UnbalancedInstruction,
844                11 => InstructionError::ModifiedProgramId,
845                12 => InstructionError::ExternalAccountLamportSpend,
846                13 => InstructionError::ExternalAccountDataModified,
847                14 => InstructionError::ReadonlyLamportChange,
848                15 => InstructionError::ReadonlyDataModified,
849                16 => InstructionError::DuplicateAccountIndex,
850                17 => InstructionError::ExecutableModified,
851                18 => InstructionError::RentEpochModified,
852                #[allow(deprecated)]
853                19 => InstructionError::NotEnoughAccountKeys,
854                20 => InstructionError::AccountDataSizeChanged,
855                21 => InstructionError::AccountNotExecutable,
856                22 => InstructionError::AccountBorrowFailed,
857                23 => InstructionError::AccountBorrowOutstanding,
858                24 => InstructionError::DuplicateAccountOutOfSync,
859                26 => InstructionError::InvalidError,
860                27 => InstructionError::ExecutableDataModified,
861                28 => InstructionError::ExecutableLamportChange,
862                29 => InstructionError::ExecutableAccountNotRentExempt,
863                30 => InstructionError::UnsupportedProgramId,
864                31 => InstructionError::CallDepth,
865                32 => InstructionError::MissingAccount,
866                33 => InstructionError::ReentrancyNotAllowed,
867                34 => InstructionError::MaxSeedLengthExceeded,
868                35 => InstructionError::InvalidSeeds,
869                36 => InstructionError::InvalidRealloc,
870                37 => InstructionError::ComputationalBudgetExceeded,
871                38 => InstructionError::PrivilegeEscalation,
872                39 => InstructionError::ProgramEnvironmentSetupFailure,
873                40 => InstructionError::ProgramFailedToComplete,
874                41 => InstructionError::ProgramFailedToCompile,
875                42 => InstructionError::Immutable,
876                43 => InstructionError::IncorrectAuthority,
877                44 => InstructionError::BorshIoError,
878                45 => InstructionError::AccountNotRentExempt,
879                46 => InstructionError::InvalidAccountOwner,
880                47 => InstructionError::ArithmeticOverflow,
881                48 => InstructionError::UnsupportedSysvar,
882                49 => InstructionError::IllegalOwner,
883                50 => InstructionError::MaxAccountsDataAllocationsExceeded,
884                51 => InstructionError::MaxAccountsExceeded,
885                52 => InstructionError::MaxInstructionTraceLengthExceeded,
886                53 => InstructionError::BuiltinProgramsMustConsumeComputeUnits,
887                _ => return Err("Invalid InstructionError"),
888            };
889
890            return Ok(TransactionError::InstructionError(
891                instruction_error.index as u8,
892                ie,
893            ));
894        }
895
896        if let Some(transaction_details) = transaction_error.transaction_details {
897            match transaction_error.transaction_error {
898                30 => {
899                    return Ok(TransactionError::DuplicateInstruction(
900                        transaction_details.index as u8,
901                    ));
902                }
903                31 => {
904                    return Ok(TransactionError::InsufficientFundsForRent {
905                        account_index: transaction_details.index as u8,
906                    });
907                }
908
909                35 => {
910                    return Ok(TransactionError::ProgramExecutionTemporarilyRestricted {
911                        account_index: transaction_details.index as u8,
912                    });
913                }
914                _ => {}
915            }
916        }
917
918        Ok(match transaction_error.transaction_error {
919            0 => TransactionError::AccountInUse,
920            1 => TransactionError::AccountLoadedTwice,
921            2 => TransactionError::AccountNotFound,
922            3 => TransactionError::ProgramAccountNotFound,
923            4 => TransactionError::InsufficientFundsForFee,
924            5 => TransactionError::InvalidAccountForFee,
925            6 => TransactionError::AlreadyProcessed,
926            7 => TransactionError::BlockhashNotFound,
927            9 => TransactionError::CallChainTooDeep,
928            10 => TransactionError::MissingSignatureForFee,
929            11 => TransactionError::InvalidAccountIndex,
930            12 => TransactionError::SignatureFailure,
931            13 => TransactionError::InvalidProgramForExecution,
932            14 => TransactionError::SanitizeFailure,
933            15 => TransactionError::ClusterMaintenance,
934            16 => TransactionError::AccountBorrowOutstanding,
935            17 => TransactionError::WouldExceedMaxBlockCostLimit,
936            18 => TransactionError::UnsupportedVersion,
937            19 => TransactionError::InvalidWritableAccount,
938            20 => TransactionError::WouldExceedMaxAccountCostLimit,
939            21 => TransactionError::WouldExceedAccountDataBlockLimit,
940            22 => TransactionError::TooManyAccountLocks,
941            23 => TransactionError::AddressLookupTableNotFound,
942            24 => TransactionError::InvalidAddressLookupTableOwner,
943            25 => TransactionError::InvalidAddressLookupTableData,
944            26 => TransactionError::InvalidAddressLookupTableIndex,
945            27 => TransactionError::InvalidRentPayingAccount,
946            28 => TransactionError::WouldExceedMaxVoteCostLimit,
947            29 => TransactionError::WouldExceedAccountDataTotalLimit,
948            32 => TransactionError::MaxLoadedAccountsDataSizeExceeded,
949            33 => TransactionError::InvalidLoadedAccountsDataSizeLimit,
950            34 => TransactionError::ResanitizationNeeded,
951            36 => TransactionError::UnbalancedTransaction,
952            37 => TransactionError::ProgramCacheHitMaxLimit,
953            38 => TransactionError::CommitCancelled,
954            _ => return Err("Invalid TransactionError"),
955        })
956    }
957}
958
959impl From<TransactionError> for tx_by_addr::TransactionError {
960    fn from(transaction_error: TransactionError) -> Self {
961        Self {
962            transaction_error: match transaction_error {
963                TransactionError::AccountInUse => tx_by_addr::TransactionErrorType::AccountInUse,
964                TransactionError::AccountLoadedTwice => {
965                    tx_by_addr::TransactionErrorType::AccountLoadedTwice
966                }
967                TransactionError::AccountNotFound => {
968                    tx_by_addr::TransactionErrorType::AccountNotFound
969                }
970                TransactionError::ProgramAccountNotFound => {
971                    tx_by_addr::TransactionErrorType::ProgramAccountNotFound
972                }
973                TransactionError::InsufficientFundsForFee => {
974                    tx_by_addr::TransactionErrorType::InsufficientFundsForFee
975                }
976                TransactionError::InvalidAccountForFee => {
977                    tx_by_addr::TransactionErrorType::InvalidAccountForFee
978                }
979                TransactionError::AlreadyProcessed => {
980                    tx_by_addr::TransactionErrorType::AlreadyProcessed
981                }
982                TransactionError::BlockhashNotFound => {
983                    tx_by_addr::TransactionErrorType::BlockhashNotFound
984                }
985                TransactionError::CallChainTooDeep => {
986                    tx_by_addr::TransactionErrorType::CallChainTooDeep
987                }
988                TransactionError::MissingSignatureForFee => {
989                    tx_by_addr::TransactionErrorType::MissingSignatureForFee
990                }
991                TransactionError::InvalidAccountIndex => {
992                    tx_by_addr::TransactionErrorType::InvalidAccountIndex
993                }
994                TransactionError::SignatureFailure => {
995                    tx_by_addr::TransactionErrorType::SignatureFailure
996                }
997                TransactionError::InvalidProgramForExecution => {
998                    tx_by_addr::TransactionErrorType::InvalidProgramForExecution
999                }
1000                TransactionError::SanitizeFailure => {
1001                    tx_by_addr::TransactionErrorType::SanitizeFailure
1002                }
1003                TransactionError::ClusterMaintenance => {
1004                    tx_by_addr::TransactionErrorType::ClusterMaintenance
1005                }
1006                TransactionError::InstructionError(_, _) => {
1007                    tx_by_addr::TransactionErrorType::InstructionError
1008                }
1009                TransactionError::AccountBorrowOutstanding => {
1010                    tx_by_addr::TransactionErrorType::AccountBorrowOutstandingTx
1011                }
1012                TransactionError::WouldExceedMaxBlockCostLimit => {
1013                    tx_by_addr::TransactionErrorType::WouldExceedMaxBlockCostLimit
1014                }
1015                TransactionError::UnsupportedVersion => {
1016                    tx_by_addr::TransactionErrorType::UnsupportedVersion
1017                }
1018                TransactionError::InvalidWritableAccount => {
1019                    tx_by_addr::TransactionErrorType::InvalidWritableAccount
1020                }
1021                TransactionError::WouldExceedMaxAccountCostLimit => {
1022                    tx_by_addr::TransactionErrorType::WouldExceedMaxAccountCostLimit
1023                }
1024                TransactionError::WouldExceedAccountDataBlockLimit => {
1025                    tx_by_addr::TransactionErrorType::WouldExceedAccountDataBlockLimit
1026                }
1027                TransactionError::TooManyAccountLocks => {
1028                    tx_by_addr::TransactionErrorType::TooManyAccountLocks
1029                }
1030                TransactionError::AddressLookupTableNotFound => {
1031                    tx_by_addr::TransactionErrorType::AddressLookupTableNotFound
1032                }
1033                TransactionError::InvalidAddressLookupTableOwner => {
1034                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableOwner
1035                }
1036                TransactionError::InvalidAddressLookupTableData => {
1037                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableData
1038                }
1039                TransactionError::InvalidAddressLookupTableIndex => {
1040                    tx_by_addr::TransactionErrorType::InvalidAddressLookupTableIndex
1041                }
1042                TransactionError::InvalidRentPayingAccount => {
1043                    tx_by_addr::TransactionErrorType::InvalidRentPayingAccount
1044                }
1045                TransactionError::WouldExceedMaxVoteCostLimit => {
1046                    tx_by_addr::TransactionErrorType::WouldExceedMaxVoteCostLimit
1047                }
1048                TransactionError::WouldExceedAccountDataTotalLimit => {
1049                    tx_by_addr::TransactionErrorType::WouldExceedAccountDataTotalLimit
1050                }
1051                TransactionError::DuplicateInstruction(_) => {
1052                    tx_by_addr::TransactionErrorType::DuplicateInstruction
1053                }
1054                TransactionError::InsufficientFundsForRent { .. } => {
1055                    tx_by_addr::TransactionErrorType::InsufficientFundsForRent
1056                }
1057                TransactionError::MaxLoadedAccountsDataSizeExceeded => {
1058                    tx_by_addr::TransactionErrorType::MaxLoadedAccountsDataSizeExceeded
1059                }
1060                TransactionError::InvalidLoadedAccountsDataSizeLimit => {
1061                    tx_by_addr::TransactionErrorType::InvalidLoadedAccountsDataSizeLimit
1062                }
1063                TransactionError::ResanitizationNeeded => {
1064                    tx_by_addr::TransactionErrorType::ResanitizationNeeded
1065                }
1066                TransactionError::ProgramExecutionTemporarilyRestricted { .. } => {
1067                    tx_by_addr::TransactionErrorType::ProgramExecutionTemporarilyRestricted
1068                }
1069                TransactionError::UnbalancedTransaction => {
1070                    tx_by_addr::TransactionErrorType::UnbalancedTransaction
1071                }
1072                TransactionError::ProgramCacheHitMaxLimit => {
1073                    tx_by_addr::TransactionErrorType::ProgramCacheHitMaxLimit
1074                }
1075                TransactionError::CommitCancelled => {
1076                    tx_by_addr::TransactionErrorType::CommitCancelled
1077                }
1078            } as i32,
1079            instruction_error: match transaction_error {
1080                TransactionError::InstructionError(index, ref instruction_error) => {
1081                    Some(tx_by_addr::InstructionError {
1082                        index: index as u32,
1083                        error: match instruction_error {
1084                            InstructionError::GenericError => {
1085                                tx_by_addr::InstructionErrorType::GenericError
1086                            }
1087                            InstructionError::InvalidArgument => {
1088                                tx_by_addr::InstructionErrorType::InvalidArgument
1089                            }
1090                            InstructionError::InvalidInstructionData => {
1091                                tx_by_addr::InstructionErrorType::InvalidInstructionData
1092                            }
1093                            InstructionError::InvalidAccountData => {
1094                                tx_by_addr::InstructionErrorType::InvalidAccountData
1095                            }
1096                            InstructionError::AccountDataTooSmall => {
1097                                tx_by_addr::InstructionErrorType::AccountDataTooSmall
1098                            }
1099                            InstructionError::InsufficientFunds => {
1100                                tx_by_addr::InstructionErrorType::InsufficientFunds
1101                            }
1102                            InstructionError::IncorrectProgramId => {
1103                                tx_by_addr::InstructionErrorType::IncorrectProgramId
1104                            }
1105                            InstructionError::MissingRequiredSignature => {
1106                                tx_by_addr::InstructionErrorType::MissingRequiredSignature
1107                            }
1108                            InstructionError::AccountAlreadyInitialized => {
1109                                tx_by_addr::InstructionErrorType::AccountAlreadyInitialized
1110                            }
1111                            InstructionError::UninitializedAccount => {
1112                                tx_by_addr::InstructionErrorType::UninitializedAccount
1113                            }
1114                            InstructionError::UnbalancedInstruction => {
1115                                tx_by_addr::InstructionErrorType::UnbalancedInstruction
1116                            }
1117                            InstructionError::ModifiedProgramId => {
1118                                tx_by_addr::InstructionErrorType::ModifiedProgramId
1119                            }
1120                            InstructionError::ExternalAccountLamportSpend => {
1121                                tx_by_addr::InstructionErrorType::ExternalAccountLamportSpend
1122                            }
1123                            InstructionError::ExternalAccountDataModified => {
1124                                tx_by_addr::InstructionErrorType::ExternalAccountDataModified
1125                            }
1126                            InstructionError::ReadonlyLamportChange => {
1127                                tx_by_addr::InstructionErrorType::ReadonlyLamportChange
1128                            }
1129                            InstructionError::ReadonlyDataModified => {
1130                                tx_by_addr::InstructionErrorType::ReadonlyDataModified
1131                            }
1132                            InstructionError::DuplicateAccountIndex => {
1133                                tx_by_addr::InstructionErrorType::DuplicateAccountIndex
1134                            }
1135                            InstructionError::ExecutableModified => {
1136                                tx_by_addr::InstructionErrorType::ExecutableModified
1137                            }
1138                            InstructionError::RentEpochModified => {
1139                                tx_by_addr::InstructionErrorType::RentEpochModified
1140                            }
1141                            #[allow(deprecated)]
1142                            InstructionError::NotEnoughAccountKeys => {
1143                                tx_by_addr::InstructionErrorType::NotEnoughAccountKeys
1144                            }
1145                            InstructionError::AccountDataSizeChanged => {
1146                                tx_by_addr::InstructionErrorType::AccountDataSizeChanged
1147                            }
1148                            InstructionError::AccountNotExecutable => {
1149                                tx_by_addr::InstructionErrorType::AccountNotExecutable
1150                            }
1151                            InstructionError::AccountBorrowFailed => {
1152                                tx_by_addr::InstructionErrorType::AccountBorrowFailed
1153                            }
1154                            InstructionError::AccountBorrowOutstanding => {
1155                                tx_by_addr::InstructionErrorType::AccountBorrowOutstanding
1156                            }
1157                            InstructionError::DuplicateAccountOutOfSync => {
1158                                tx_by_addr::InstructionErrorType::DuplicateAccountOutOfSync
1159                            }
1160                            InstructionError::Custom(_) => tx_by_addr::InstructionErrorType::Custom,
1161                            InstructionError::InvalidError => {
1162                                tx_by_addr::InstructionErrorType::InvalidError
1163                            }
1164                            InstructionError::ExecutableDataModified => {
1165                                tx_by_addr::InstructionErrorType::ExecutableDataModified
1166                            }
1167                            InstructionError::ExecutableLamportChange => {
1168                                tx_by_addr::InstructionErrorType::ExecutableLamportChange
1169                            }
1170                            InstructionError::ExecutableAccountNotRentExempt => {
1171                                tx_by_addr::InstructionErrorType::ExecutableAccountNotRentExempt
1172                            }
1173                            InstructionError::UnsupportedProgramId => {
1174                                tx_by_addr::InstructionErrorType::UnsupportedProgramId
1175                            }
1176                            InstructionError::CallDepth => {
1177                                tx_by_addr::InstructionErrorType::CallDepth
1178                            }
1179                            InstructionError::MissingAccount => {
1180                                tx_by_addr::InstructionErrorType::MissingAccount
1181                            }
1182                            InstructionError::ReentrancyNotAllowed => {
1183                                tx_by_addr::InstructionErrorType::ReentrancyNotAllowed
1184                            }
1185                            InstructionError::MaxSeedLengthExceeded => {
1186                                tx_by_addr::InstructionErrorType::MaxSeedLengthExceeded
1187                            }
1188                            InstructionError::InvalidSeeds => {
1189                                tx_by_addr::InstructionErrorType::InvalidSeeds
1190                            }
1191                            InstructionError::InvalidRealloc => {
1192                                tx_by_addr::InstructionErrorType::InvalidRealloc
1193                            }
1194                            InstructionError::ComputationalBudgetExceeded => {
1195                                tx_by_addr::InstructionErrorType::ComputationalBudgetExceeded
1196                            }
1197                            InstructionError::PrivilegeEscalation => {
1198                                tx_by_addr::InstructionErrorType::PrivilegeEscalation
1199                            }
1200                            InstructionError::ProgramEnvironmentSetupFailure => {
1201                                tx_by_addr::InstructionErrorType::ProgramEnvironmentSetupFailure
1202                            }
1203                            InstructionError::ProgramFailedToComplete => {
1204                                tx_by_addr::InstructionErrorType::ProgramFailedToComplete
1205                            }
1206                            InstructionError::ProgramFailedToCompile => {
1207                                tx_by_addr::InstructionErrorType::ProgramFailedToCompile
1208                            }
1209                            InstructionError::Immutable => {
1210                                tx_by_addr::InstructionErrorType::Immutable
1211                            }
1212                            InstructionError::IncorrectAuthority => {
1213                                tx_by_addr::InstructionErrorType::IncorrectAuthority
1214                            }
1215                            InstructionError::BorshIoError => {
1216                                tx_by_addr::InstructionErrorType::BorshIoError
1217                            }
1218                            InstructionError::AccountNotRentExempt => {
1219                                tx_by_addr::InstructionErrorType::AccountNotRentExempt
1220                            }
1221                            InstructionError::InvalidAccountOwner => {
1222                                tx_by_addr::InstructionErrorType::InvalidAccountOwner
1223                            }
1224                            InstructionError::ArithmeticOverflow => {
1225                                tx_by_addr::InstructionErrorType::ArithmeticOverflow
1226                            }
1227                            InstructionError::UnsupportedSysvar => {
1228                                tx_by_addr::InstructionErrorType::UnsupportedSysvar
1229                            }
1230                            InstructionError::IllegalOwner => {
1231                                tx_by_addr::InstructionErrorType::IllegalOwner
1232                            }
1233                            InstructionError::MaxAccountsDataAllocationsExceeded => {
1234                                tx_by_addr::InstructionErrorType::MaxAccountsDataAllocationsExceeded
1235                            }
1236                            InstructionError::MaxAccountsExceeded => {
1237                                tx_by_addr::InstructionErrorType::MaxAccountsExceeded
1238                            }
1239                            InstructionError::MaxInstructionTraceLengthExceeded => {
1240                                tx_by_addr::InstructionErrorType::MaxInstructionTraceLengthExceeded
1241                            }
1242                            InstructionError::BuiltinProgramsMustConsumeComputeUnits => {
1243                                tx_by_addr::InstructionErrorType::BuiltinProgramsMustConsumeComputeUnits
1244                            }
1245                        } as i32,
1246                        custom: match instruction_error {
1247                            InstructionError::Custom(custom) => {
1248                                Some(tx_by_addr::CustomError { custom: *custom })
1249                            }
1250                            _ => None,
1251                        },
1252                    })
1253                }
1254                _ => None,
1255            },
1256            transaction_details: match transaction_error {
1257                TransactionError::DuplicateInstruction(index) => {
1258                    Some(tx_by_addr::TransactionDetails {
1259                        index: index as u32,
1260                    })
1261                }
1262                TransactionError::InsufficientFundsForRent { account_index } => {
1263                    Some(tx_by_addr::TransactionDetails {
1264                        index: account_index as u32,
1265                    })
1266                }
1267                TransactionError::ProgramExecutionTemporarilyRestricted { account_index } => {
1268                    Some(tx_by_addr::TransactionDetails {
1269                        index: account_index as u32,
1270                    })
1271                }
1272
1273                _ => None,
1274            },
1275        }
1276    }
1277}
1278
1279impl From<TransactionByAddrInfo> for tx_by_addr::TransactionByAddrInfo {
1280    fn from(by_addr: TransactionByAddrInfo) -> Self {
1281        let TransactionByAddrInfo {
1282            signature,
1283            err,
1284            index,
1285            memo,
1286            block_time,
1287        } = by_addr;
1288
1289        Self {
1290            signature: <Signature as AsRef<[u8]>>::as_ref(&signature).into(),
1291            err: err.map(|e| e.into()),
1292            index,
1293            memo: memo.map(|memo| tx_by_addr::Memo { memo }),
1294            block_time: block_time.map(|timestamp| tx_by_addr::UnixTimestamp { timestamp }),
1295        }
1296    }
1297}
1298
1299impl TryFrom<tx_by_addr::TransactionByAddrInfo> for TransactionByAddrInfo {
1300    type Error = &'static str;
1301
1302    fn try_from(
1303        transaction_by_addr: tx_by_addr::TransactionByAddrInfo,
1304    ) -> Result<Self, Self::Error> {
1305        let err = transaction_by_addr
1306            .err
1307            .map(|err| err.try_into())
1308            .transpose()?;
1309
1310        Ok(Self {
1311            signature: Signature::try_from(transaction_by_addr.signature)
1312                .map_err(|_| "Invalid Signature")?,
1313            err,
1314            index: transaction_by_addr.index,
1315            memo: transaction_by_addr
1316                .memo
1317                .map(|tx_by_addr::Memo { memo }| memo),
1318            block_time: transaction_by_addr
1319                .block_time
1320                .map(|tx_by_addr::UnixTimestamp { timestamp }| timestamp),
1321        })
1322    }
1323}
1324
1325impl TryFrom<tx_by_addr::TransactionByAddr> for Vec<TransactionByAddrInfo> {
1326    type Error = &'static str;
1327
1328    fn try_from(collection: tx_by_addr::TransactionByAddr) -> Result<Self, Self::Error> {
1329        collection
1330            .tx_by_addrs
1331            .into_iter()
1332            .map(|tx_by_addr| tx_by_addr.try_into())
1333            .collect::<Result<Vec<TransactionByAddrInfo>, Self::Error>>()
1334    }
1335}
1336
1337impl From<(usize, EntrySummary)> for entries::Entry {
1338    fn from((index, entry_summary): (usize, EntrySummary)) -> Self {
1339        entries::Entry {
1340            index: index as u32,
1341            num_hashes: entry_summary.num_hashes,
1342            hash: entry_summary.hash.as_ref().into(),
1343            num_transactions: entry_summary.num_transactions,
1344            starting_transaction_index: entry_summary.starting_transaction_index as u32,
1345        }
1346    }
1347}
1348
1349impl From<entries::Entry> for EntrySummary {
1350    fn from(entry: entries::Entry) -> Self {
1351        EntrySummary {
1352            num_hashes: entry.num_hashes,
1353            hash: <[u8; HASH_BYTES]>::try_from(entry.hash)
1354                .map(Hash::new_from_array)
1355                .unwrap(),
1356            num_transactions: entry.num_transactions,
1357            starting_transaction_index: entry.starting_transaction_index as usize,
1358        }
1359    }
1360}
1361
1362#[cfg(test)]
1363mod test {
1364    use {super::*, enum_iterator::all};
1365
1366    fn header() -> MessageHeader {
1367        MessageHeader {
1368            num_required_signatures: 1,
1369            num_readonly_signed_accounts: 0,
1370            num_readonly_unsigned_accounts: 1,
1371        }
1372    }
1373
1374    fn account_keys() -> Vec<Pubkey> {
1375        vec![
1376            Pubkey::new_unique(),
1377            Pubkey::new_unique(),
1378            Pubkey::new_unique(),
1379        ]
1380    }
1381
1382    fn instructions() -> Vec<CompiledInstruction> {
1383        vec![CompiledInstruction {
1384            program_id_index: 2,
1385            accounts: vec![0, 1],
1386            data: vec![1, 2, 3, 4],
1387        }]
1388    }
1389
1390    fn round_trip(message: VersionedMessage) -> VersionedMessage {
1391        VersionedMessage::from(generated::Message::from(message))
1392    }
1393
1394    #[test]
1395    fn test_reward_type_encode() {
1396        let mut reward = Reward {
1397            pubkey: "invalid".to_string(),
1398            lamports: 123,
1399            post_balance: 321,
1400            reward_type: None,
1401            commission: None,
1402            commission_bps: None,
1403        };
1404        let gen_reward: generated::Reward = reward.clone().into();
1405        assert_eq!(reward, gen_reward.into());
1406
1407        reward.reward_type = Some(RewardType::Fee);
1408        let gen_reward: generated::Reward = reward.clone().into();
1409        assert_eq!(reward, gen_reward.into());
1410
1411        reward.reward_type = Some(RewardType::Rent);
1412        let gen_reward: generated::Reward = reward.clone().into();
1413        assert_eq!(reward, gen_reward.into());
1414
1415        reward.reward_type = Some(RewardType::Voting);
1416        let gen_reward: generated::Reward = reward.clone().into();
1417        assert_eq!(reward, gen_reward.into());
1418
1419        reward.reward_type = Some(RewardType::Staking);
1420        let gen_reward: generated::Reward = reward.clone().into();
1421        assert_eq!(reward, gen_reward.into());
1422
1423        reward.reward_type = Some(RewardType::DeactivatedStake);
1424        let gen_reward: generated::Reward = reward.clone().into();
1425        assert_eq!(reward, gen_reward.into());
1426    }
1427
1428    #[test]
1429    fn test_transaction_by_addr_encode() {
1430        let info = TransactionByAddrInfo {
1431            signature: bs58::decode("Nfo6rgemG1KLbk1xuNwfrQTsdxaGfLuWURHNRy9LYnDrubG7LFQZaA5obPNas9LQ6DdorJqxh2LxA3PsnWdkSrL")
1432                .into_vec()
1433                .map(Signature::try_from)
1434                .unwrap()
1435                .unwrap(),
1436            err: None,
1437            index: 5,
1438            memo: Some("string".to_string()),
1439            block_time: Some(1610674861)
1440        };
1441
1442        let tx_by_addr_transaction_info: tx_by_addr::TransactionByAddrInfo = info.clone().into();
1443        assert_eq!(info, tx_by_addr_transaction_info.try_into().unwrap());
1444    }
1445
1446    #[test]
1447    fn test_transaction_error_encode() {
1448        let transaction_error = TransactionError::AccountBorrowOutstanding;
1449        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1450            transaction_error.clone().into();
1451        assert_eq!(
1452            transaction_error,
1453            tx_by_addr_transaction_error.try_into().unwrap()
1454        );
1455
1456        let transaction_error = TransactionError::AccountInUse;
1457        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1458            transaction_error.clone().into();
1459        assert_eq!(
1460            transaction_error,
1461            tx_by_addr_transaction_error.try_into().unwrap()
1462        );
1463
1464        let transaction_error = TransactionError::AccountLoadedTwice;
1465        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1466            transaction_error.clone().into();
1467        assert_eq!(
1468            transaction_error,
1469            tx_by_addr_transaction_error.try_into().unwrap()
1470        );
1471
1472        let transaction_error = TransactionError::AccountNotFound;
1473        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1474            transaction_error.clone().into();
1475        assert_eq!(
1476            transaction_error,
1477            tx_by_addr_transaction_error.try_into().unwrap()
1478        );
1479
1480        let transaction_error = TransactionError::AlreadyProcessed;
1481        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1482            transaction_error.clone().into();
1483        assert_eq!(
1484            transaction_error,
1485            tx_by_addr_transaction_error.try_into().unwrap()
1486        );
1487
1488        let transaction_error = TransactionError::BlockhashNotFound;
1489        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1490            transaction_error.clone().into();
1491        assert_eq!(
1492            transaction_error,
1493            tx_by_addr_transaction_error.try_into().unwrap()
1494        );
1495
1496        let transaction_error = TransactionError::CallChainTooDeep;
1497        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1498            transaction_error.clone().into();
1499        assert_eq!(
1500            transaction_error,
1501            tx_by_addr_transaction_error.try_into().unwrap()
1502        );
1503
1504        let transaction_error = TransactionError::ClusterMaintenance;
1505        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1506            transaction_error.clone().into();
1507        assert_eq!(
1508            transaction_error,
1509            tx_by_addr_transaction_error.try_into().unwrap()
1510        );
1511
1512        let transaction_error = TransactionError::InsufficientFundsForFee;
1513        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1514            transaction_error.clone().into();
1515        assert_eq!(
1516            transaction_error,
1517            tx_by_addr_transaction_error.try_into().unwrap()
1518        );
1519
1520        let transaction_error = TransactionError::InvalidAccountForFee;
1521        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1522            transaction_error.clone().into();
1523        assert_eq!(
1524            transaction_error,
1525            tx_by_addr_transaction_error.try_into().unwrap()
1526        );
1527
1528        let transaction_error = TransactionError::InvalidAccountIndex;
1529        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1530            transaction_error.clone().into();
1531        assert_eq!(
1532            transaction_error,
1533            tx_by_addr_transaction_error.try_into().unwrap()
1534        );
1535
1536        let transaction_error = TransactionError::InvalidProgramForExecution;
1537        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1538            transaction_error.clone().into();
1539        assert_eq!(
1540            transaction_error,
1541            tx_by_addr_transaction_error.try_into().unwrap()
1542        );
1543
1544        let transaction_error = TransactionError::MissingSignatureForFee;
1545        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1546            transaction_error.clone().into();
1547        assert_eq!(
1548            transaction_error,
1549            tx_by_addr_transaction_error.try_into().unwrap()
1550        );
1551
1552        let transaction_error = TransactionError::ProgramAccountNotFound;
1553        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1554            transaction_error.clone().into();
1555        assert_eq!(
1556            transaction_error,
1557            tx_by_addr_transaction_error.try_into().unwrap()
1558        );
1559
1560        let transaction_error = TransactionError::SanitizeFailure;
1561        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1562            transaction_error.clone().into();
1563        assert_eq!(
1564            transaction_error,
1565            tx_by_addr_transaction_error.try_into().unwrap()
1566        );
1567
1568        let transaction_error = TransactionError::SignatureFailure;
1569        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1570            transaction_error.clone().into();
1571        assert_eq!(
1572            transaction_error,
1573            tx_by_addr_transaction_error.try_into().unwrap()
1574        );
1575
1576        let transaction_error = TransactionError::WouldExceedMaxBlockCostLimit;
1577        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1578            transaction_error.clone().into();
1579        assert_eq!(
1580            transaction_error,
1581            tx_by_addr_transaction_error.try_into().unwrap()
1582        );
1583
1584        let transaction_error = TransactionError::WouldExceedMaxVoteCostLimit;
1585        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1586            transaction_error.clone().into();
1587        assert_eq!(
1588            transaction_error,
1589            tx_by_addr_transaction_error.try_into().unwrap()
1590        );
1591
1592        let transaction_error = TransactionError::WouldExceedMaxAccountCostLimit;
1593        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1594            transaction_error.clone().into();
1595        assert_eq!(
1596            transaction_error,
1597            tx_by_addr_transaction_error.try_into().unwrap()
1598        );
1599
1600        let transaction_error = TransactionError::UnsupportedVersion;
1601        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1602            transaction_error.clone().into();
1603        assert_eq!(
1604            transaction_error,
1605            tx_by_addr_transaction_error.try_into().unwrap()
1606        );
1607
1608        let transaction_error =
1609            TransactionError::InstructionError(10, InstructionError::AccountAlreadyInitialized);
1610        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1611            transaction_error.clone().into();
1612        assert_eq!(
1613            transaction_error,
1614            tx_by_addr_transaction_error.try_into().unwrap()
1615        );
1616
1617        let transaction_error =
1618            TransactionError::InstructionError(10, InstructionError::AccountBorrowFailed);
1619        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1620            transaction_error.clone().into();
1621        assert_eq!(
1622            transaction_error,
1623            tx_by_addr_transaction_error.try_into().unwrap()
1624        );
1625
1626        let transaction_error =
1627            TransactionError::InstructionError(10, InstructionError::AccountBorrowOutstanding);
1628        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1629            transaction_error.clone().into();
1630        assert_eq!(
1631            transaction_error,
1632            tx_by_addr_transaction_error.try_into().unwrap()
1633        );
1634
1635        let transaction_error =
1636            TransactionError::InstructionError(10, InstructionError::AccountDataSizeChanged);
1637        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1638            transaction_error.clone().into();
1639        assert_eq!(
1640            transaction_error,
1641            tx_by_addr_transaction_error.try_into().unwrap()
1642        );
1643
1644        let transaction_error =
1645            TransactionError::InstructionError(10, InstructionError::AccountDataTooSmall);
1646        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1647            transaction_error.clone().into();
1648        assert_eq!(
1649            transaction_error,
1650            tx_by_addr_transaction_error.try_into().unwrap()
1651        );
1652
1653        let transaction_error =
1654            TransactionError::InstructionError(10, InstructionError::AccountNotExecutable);
1655        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1656            transaction_error.clone().into();
1657        assert_eq!(
1658            transaction_error,
1659            tx_by_addr_transaction_error.try_into().unwrap()
1660        );
1661
1662        let transaction_error = TransactionError::InstructionError(10, InstructionError::CallDepth);
1663        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1664            transaction_error.clone().into();
1665        assert_eq!(
1666            transaction_error,
1667            tx_by_addr_transaction_error.try_into().unwrap()
1668        );
1669
1670        let transaction_error =
1671            TransactionError::InstructionError(10, InstructionError::ComputationalBudgetExceeded);
1672        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1673            transaction_error.clone().into();
1674        assert_eq!(
1675            transaction_error,
1676            tx_by_addr_transaction_error.try_into().unwrap()
1677        );
1678
1679        let transaction_error =
1680            TransactionError::InstructionError(10, InstructionError::DuplicateAccountIndex);
1681        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1682            transaction_error.clone().into();
1683        assert_eq!(
1684            transaction_error,
1685            tx_by_addr_transaction_error.try_into().unwrap()
1686        );
1687
1688        let transaction_error =
1689            TransactionError::InstructionError(10, InstructionError::DuplicateAccountOutOfSync);
1690        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1691            transaction_error.clone().into();
1692        assert_eq!(
1693            transaction_error,
1694            tx_by_addr_transaction_error.try_into().unwrap()
1695        );
1696
1697        let transaction_error = TransactionError::InstructionError(
1698            10,
1699            InstructionError::ExecutableAccountNotRentExempt,
1700        );
1701        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1702            transaction_error.clone().into();
1703        assert_eq!(
1704            transaction_error,
1705            tx_by_addr_transaction_error.try_into().unwrap()
1706        );
1707
1708        let transaction_error =
1709            TransactionError::InstructionError(10, InstructionError::ExecutableDataModified);
1710        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1711            transaction_error.clone().into();
1712        assert_eq!(
1713            transaction_error,
1714            tx_by_addr_transaction_error.try_into().unwrap()
1715        );
1716
1717        let transaction_error =
1718            TransactionError::InstructionError(10, InstructionError::ExecutableLamportChange);
1719        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1720            transaction_error.clone().into();
1721        assert_eq!(
1722            transaction_error,
1723            tx_by_addr_transaction_error.try_into().unwrap()
1724        );
1725
1726        let transaction_error =
1727            TransactionError::InstructionError(10, InstructionError::ExecutableModified);
1728        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1729            transaction_error.clone().into();
1730        assert_eq!(
1731            transaction_error,
1732            tx_by_addr_transaction_error.try_into().unwrap()
1733        );
1734
1735        let transaction_error =
1736            TransactionError::InstructionError(10, InstructionError::ExternalAccountDataModified);
1737        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1738            transaction_error.clone().into();
1739        assert_eq!(
1740            transaction_error,
1741            tx_by_addr_transaction_error.try_into().unwrap()
1742        );
1743
1744        let transaction_error =
1745            TransactionError::InstructionError(10, InstructionError::ExternalAccountLamportSpend);
1746        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1747            transaction_error.clone().into();
1748        assert_eq!(
1749            transaction_error,
1750            tx_by_addr_transaction_error.try_into().unwrap()
1751        );
1752
1753        let transaction_error =
1754            TransactionError::InstructionError(10, InstructionError::GenericError);
1755        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1756            transaction_error.clone().into();
1757        assert_eq!(
1758            transaction_error,
1759            tx_by_addr_transaction_error.try_into().unwrap()
1760        );
1761
1762        let transaction_error = TransactionError::InstructionError(10, InstructionError::Immutable);
1763        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1764            transaction_error.clone().into();
1765        assert_eq!(
1766            transaction_error,
1767            tx_by_addr_transaction_error.try_into().unwrap()
1768        );
1769
1770        let transaction_error =
1771            TransactionError::InstructionError(10, InstructionError::IncorrectAuthority);
1772        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1773            transaction_error.clone().into();
1774        assert_eq!(
1775            transaction_error,
1776            tx_by_addr_transaction_error.try_into().unwrap()
1777        );
1778
1779        let transaction_error =
1780            TransactionError::InstructionError(10, InstructionError::IncorrectProgramId);
1781        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1782            transaction_error.clone().into();
1783        assert_eq!(
1784            transaction_error,
1785            tx_by_addr_transaction_error.try_into().unwrap()
1786        );
1787
1788        let transaction_error =
1789            TransactionError::InstructionError(10, InstructionError::InsufficientFunds);
1790        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1791            transaction_error.clone().into();
1792        assert_eq!(
1793            transaction_error,
1794            tx_by_addr_transaction_error.try_into().unwrap()
1795        );
1796
1797        let transaction_error =
1798            TransactionError::InstructionError(10, InstructionError::InvalidAccountData);
1799        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1800            transaction_error.clone().into();
1801        assert_eq!(
1802            transaction_error,
1803            tx_by_addr_transaction_error.try_into().unwrap()
1804        );
1805
1806        let transaction_error =
1807            TransactionError::InstructionError(10, InstructionError::InvalidArgument);
1808        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1809            transaction_error.clone().into();
1810        assert_eq!(
1811            transaction_error,
1812            tx_by_addr_transaction_error.try_into().unwrap()
1813        );
1814
1815        let transaction_error =
1816            TransactionError::InstructionError(10, InstructionError::InvalidError);
1817        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1818            transaction_error.clone().into();
1819        assert_eq!(
1820            transaction_error,
1821            tx_by_addr_transaction_error.try_into().unwrap()
1822        );
1823
1824        let transaction_error =
1825            TransactionError::InstructionError(10, InstructionError::InvalidInstructionData);
1826        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1827            transaction_error.clone().into();
1828        assert_eq!(
1829            transaction_error,
1830            tx_by_addr_transaction_error.try_into().unwrap()
1831        );
1832
1833        let transaction_error =
1834            TransactionError::InstructionError(10, InstructionError::InvalidRealloc);
1835        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1836            transaction_error.clone().into();
1837        assert_eq!(
1838            transaction_error,
1839            tx_by_addr_transaction_error.try_into().unwrap()
1840        );
1841
1842        let transaction_error =
1843            TransactionError::InstructionError(10, InstructionError::InvalidSeeds);
1844        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1845            transaction_error.clone().into();
1846        assert_eq!(
1847            transaction_error,
1848            tx_by_addr_transaction_error.try_into().unwrap()
1849        );
1850
1851        let transaction_error =
1852            TransactionError::InstructionError(10, InstructionError::MaxSeedLengthExceeded);
1853        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1854            transaction_error.clone().into();
1855        assert_eq!(
1856            transaction_error,
1857            tx_by_addr_transaction_error.try_into().unwrap()
1858        );
1859
1860        let transaction_error =
1861            TransactionError::InstructionError(10, InstructionError::MissingAccount);
1862        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1863            transaction_error.clone().into();
1864        assert_eq!(
1865            transaction_error,
1866            tx_by_addr_transaction_error.try_into().unwrap()
1867        );
1868
1869        let transaction_error =
1870            TransactionError::InstructionError(10, InstructionError::MissingRequiredSignature);
1871        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1872            transaction_error.clone().into();
1873        assert_eq!(
1874            transaction_error,
1875            tx_by_addr_transaction_error.try_into().unwrap()
1876        );
1877
1878        let transaction_error =
1879            TransactionError::InstructionError(10, InstructionError::ModifiedProgramId);
1880        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1881            transaction_error.clone().into();
1882        assert_eq!(
1883            transaction_error,
1884            tx_by_addr_transaction_error.try_into().unwrap()
1885        );
1886
1887        #[allow(deprecated)]
1888        let transaction_error =
1889            TransactionError::InstructionError(10, InstructionError::NotEnoughAccountKeys);
1890        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1891            transaction_error.clone().into();
1892        assert_eq!(
1893            transaction_error,
1894            tx_by_addr_transaction_error.try_into().unwrap()
1895        );
1896
1897        let transaction_error =
1898            TransactionError::InstructionError(10, InstructionError::PrivilegeEscalation);
1899        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1900            transaction_error.clone().into();
1901        assert_eq!(
1902            transaction_error,
1903            tx_by_addr_transaction_error.try_into().unwrap()
1904        );
1905
1906        let transaction_error = TransactionError::InstructionError(
1907            10,
1908            InstructionError::ProgramEnvironmentSetupFailure,
1909        );
1910        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1911            transaction_error.clone().into();
1912        assert_eq!(
1913            transaction_error,
1914            tx_by_addr_transaction_error.try_into().unwrap()
1915        );
1916
1917        let transaction_error =
1918            TransactionError::InstructionError(10, InstructionError::ProgramFailedToCompile);
1919        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1920            transaction_error.clone().into();
1921        assert_eq!(
1922            transaction_error,
1923            tx_by_addr_transaction_error.try_into().unwrap()
1924        );
1925
1926        let transaction_error =
1927            TransactionError::InstructionError(10, InstructionError::ProgramFailedToComplete);
1928        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1929            transaction_error.clone().into();
1930        assert_eq!(
1931            transaction_error,
1932            tx_by_addr_transaction_error.try_into().unwrap()
1933        );
1934
1935        let transaction_error =
1936            TransactionError::InstructionError(10, InstructionError::ReadonlyDataModified);
1937        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1938            transaction_error.clone().into();
1939        assert_eq!(
1940            transaction_error,
1941            tx_by_addr_transaction_error.try_into().unwrap()
1942        );
1943
1944        let transaction_error =
1945            TransactionError::InstructionError(10, InstructionError::ReadonlyLamportChange);
1946        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1947            transaction_error.clone().into();
1948        assert_eq!(
1949            transaction_error,
1950            tx_by_addr_transaction_error.try_into().unwrap()
1951        );
1952
1953        let transaction_error =
1954            TransactionError::InstructionError(10, InstructionError::ReentrancyNotAllowed);
1955        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1956            transaction_error.clone().into();
1957        assert_eq!(
1958            transaction_error,
1959            tx_by_addr_transaction_error.try_into().unwrap()
1960        );
1961
1962        let transaction_error =
1963            TransactionError::InstructionError(10, InstructionError::RentEpochModified);
1964        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1965            transaction_error.clone().into();
1966        assert_eq!(
1967            transaction_error,
1968            tx_by_addr_transaction_error.try_into().unwrap()
1969        );
1970
1971        let transaction_error =
1972            TransactionError::InstructionError(10, InstructionError::UnbalancedInstruction);
1973        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1974            transaction_error.clone().into();
1975        assert_eq!(
1976            transaction_error,
1977            tx_by_addr_transaction_error.try_into().unwrap()
1978        );
1979
1980        let transaction_error =
1981            TransactionError::InstructionError(10, InstructionError::UninitializedAccount);
1982        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1983            transaction_error.clone().into();
1984        assert_eq!(
1985            transaction_error,
1986            tx_by_addr_transaction_error.try_into().unwrap()
1987        );
1988
1989        let transaction_error =
1990            TransactionError::InstructionError(10, InstructionError::UnsupportedProgramId);
1991        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
1992            transaction_error.clone().into();
1993        assert_eq!(
1994            transaction_error,
1995            tx_by_addr_transaction_error.try_into().unwrap()
1996        );
1997
1998        let transaction_error =
1999            TransactionError::InstructionError(10, InstructionError::Custom(10));
2000        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
2001            transaction_error.clone().into();
2002        assert_eq!(
2003            transaction_error,
2004            tx_by_addr_transaction_error.try_into().unwrap()
2005        );
2006
2007        let transaction_error = TransactionError::DuplicateInstruction(10);
2008        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
2009            transaction_error.clone().into();
2010        assert_eq!(
2011            transaction_error,
2012            tx_by_addr_transaction_error.try_into().unwrap()
2013        );
2014
2015        let transaction_error = TransactionError::InsufficientFundsForRent { account_index: 10 };
2016        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
2017            transaction_error.clone().into();
2018        assert_eq!(
2019            transaction_error,
2020            tx_by_addr_transaction_error.try_into().unwrap()
2021        );
2022
2023        let transaction_error = TransactionError::UnbalancedTransaction;
2024        let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
2025            transaction_error.clone().into();
2026        assert_eq!(
2027            transaction_error,
2028            tx_by_addr_transaction_error.try_into().unwrap()
2029        );
2030    }
2031
2032    #[test]
2033    fn test_error_enums() {
2034        let ix_index = 1;
2035        let custom_error = 42;
2036        for error in all::<tx_by_addr::TransactionErrorType>() {
2037            match error {
2038                tx_by_addr::TransactionErrorType::DuplicateInstruction
2039                | tx_by_addr::TransactionErrorType::InsufficientFundsForRent
2040                | tx_by_addr::TransactionErrorType::ProgramExecutionTemporarilyRestricted => {
2041                    let tx_by_addr_error = tx_by_addr::TransactionError {
2042                        transaction_error: error as i32,
2043                        instruction_error: None,
2044                        transaction_details: Some(tx_by_addr::TransactionDetails {
2045                            index: ix_index,
2046                        }),
2047                    };
2048                    let transaction_error: TransactionError = tx_by_addr_error
2049                        .try_into()
2050                        .unwrap_or_else(|_| panic!("{error:?} conversion implemented?"));
2051                    assert_eq!(tx_by_addr_error, transaction_error.into());
2052                }
2053                tx_by_addr::TransactionErrorType::InstructionError => {
2054                    for ix_error in all::<tx_by_addr::InstructionErrorType>() {
2055                        if ix_error != tx_by_addr::InstructionErrorType::Custom {
2056                            let tx_by_addr_error = tx_by_addr::TransactionError {
2057                                transaction_error: error as i32,
2058                                instruction_error: Some(tx_by_addr::InstructionError {
2059                                    index: ix_index,
2060                                    error: ix_error as i32,
2061                                    custom: None,
2062                                }),
2063                                transaction_details: None,
2064                            };
2065                            let transaction_error: TransactionError = tx_by_addr_error
2066                                .try_into()
2067                                .unwrap_or_else(|_| panic!("{ix_error:?} conversion implemented?"));
2068                            assert_eq!(tx_by_addr_error, transaction_error.into());
2069                        } else {
2070                            let tx_by_addr_error = tx_by_addr::TransactionError {
2071                                transaction_error: error as i32,
2072                                instruction_error: Some(tx_by_addr::InstructionError {
2073                                    index: ix_index,
2074                                    error: ix_error as i32,
2075                                    custom: Some(tx_by_addr::CustomError {
2076                                        custom: custom_error,
2077                                    }),
2078                                }),
2079                                transaction_details: None,
2080                            };
2081                            let transaction_error: TransactionError =
2082                                tx_by_addr_error.try_into().unwrap();
2083                            assert_eq!(tx_by_addr_error, transaction_error.into());
2084                        }
2085                    }
2086                }
2087                _ => {
2088                    let tx_by_addr_error = tx_by_addr::TransactionError {
2089                        transaction_error: error as i32,
2090                        instruction_error: None,
2091                        transaction_details: None,
2092                    };
2093                    let transaction_error: TransactionError = tx_by_addr_error
2094                        .try_into()
2095                        .unwrap_or_else(|_| panic!("{error:?} conversion implemented?"));
2096                    assert_eq!(tx_by_addr_error, transaction_error.into());
2097                }
2098            }
2099        }
2100    }
2101
2102    #[test]
2103    fn legacy_message_round_trips() {
2104        let message = VersionedMessage::Legacy(LegacyMessage {
2105            header: header(),
2106            account_keys: account_keys(),
2107            recent_blockhash: Hash::new_unique(),
2108            instructions: instructions(),
2109        });
2110        assert_eq!(round_trip(message.clone()), message);
2111    }
2112
2113    #[test]
2114    fn v0_message_round_trips() {
2115        let message = VersionedMessage::V0(v0::Message {
2116            header: header(),
2117            account_keys: account_keys(),
2118            recent_blockhash: Hash::new_unique(),
2119            instructions: instructions(),
2120            address_table_lookups: vec![MessageAddressTableLookup {
2121                account_key: Pubkey::new_unique(),
2122                writable_indexes: vec![1, 2],
2123                readonly_indexes: vec![3],
2124            }],
2125        });
2126        assert_eq!(round_trip(message.clone()), message);
2127    }
2128
2129    /// `versioned` is true for V0 and V1 alike, so a V1 message is only recognisable by the
2130    /// presence of `config`. Reading it back as V0 would silently drop the compute-budget request
2131    /// and misreport the version.
2132    #[test]
2133    fn v1_message_round_trips() {
2134        let message = VersionedMessage::V1(v1::Message {
2135            header: header(),
2136            config: v1::TransactionConfig::empty()
2137                .with_priority_fee(5_000)
2138                .with_compute_unit_limit(30_000)
2139                .with_loaded_accounts_data_size_limit(200_000)
2140                .with_heap_size(65_536),
2141            lifetime_specifier: Hash::new_unique(),
2142            account_keys: account_keys(),
2143            instructions: instructions(),
2144        });
2145        assert_eq!(round_trip(message.clone()), message);
2146    }
2147
2148    /// A V1 message may request nothing at all — an empty config mask is legal, and must still be
2149    /// distinguishable from V0.
2150    #[test]
2151    fn v1_message_with_empty_config_round_trips() {
2152        let message = VersionedMessage::V1(v1::Message {
2153            header: header(),
2154            config: v1::TransactionConfig::empty(),
2155            lifetime_specifier: Hash::new_unique(),
2156            account_keys: account_keys(),
2157            instructions: instructions(),
2158        });
2159        assert_eq!(round_trip(message.clone()), message);
2160    }
2161}