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