data_anchor_client/batch_client/
transaction.rs1use solana_client::client_error::ClientError as Error;
2use solana_sdk::{
3 clock::Slot, commitment_config::CommitmentConfig, signature::Signature,
4 transaction::TransactionError,
5};
6use solana_transaction_status::TransactionStatus as SolanaTransactionStatus;
7
8#[derive(Debug)]
11pub enum TransactionOutcome<T> {
12 Success(SuccessfulTransaction<T>),
14 Unknown(UnknownTransaction<T>),
16 Failure(FailedTransaction<T>),
18}
19
20#[derive(Debug)]
22pub struct SuccessfulTransaction<T> {
23 pub data: T,
24 pub slot: Slot,
25 pub signature: Signature,
26}
27
28#[derive(Debug)]
30pub struct UnknownTransaction<T> {
31 pub data: T,
32}
33
34#[derive(Debug)]
36pub struct FailedTransaction<T> {
37 pub data: T,
38 pub error: Error,
39 pub logs: Vec<String>,
40}
41
42impl<T> TransactionOutcome<T> {
43 pub fn successful(&self) -> bool {
45 match self {
46 TransactionOutcome::Success(_) => true,
47 TransactionOutcome::Unknown(_) | TransactionOutcome::Failure(_) => false,
48 }
49 }
50
51 pub fn into_successful(self) -> Option<SuccessfulTransaction<T>> {
53 match self {
54 TransactionOutcome::Success(s) => Some(s),
55 TransactionOutcome::Unknown(_) | TransactionOutcome::Failure(_) => None,
56 }
57 }
58
59 pub fn error(&self) -> Option<&FailedTransaction<T>> {
61 match self {
62 TransactionOutcome::Success(_) => None,
63 TransactionOutcome::Unknown(_) => None,
64 TransactionOutcome::Failure(f) => Some(f),
65 }
66 }
67}
68
69pub struct TransactionProgress<T> {
71 pub data: T,
72 pub landed_as: Option<(Slot, Signature)>,
73 pub status: TransactionStatus,
74}
75
76impl<T> TransactionProgress<T> {
77 pub fn new(data: T) -> Self {
78 Self {
79 data,
80 landed_as: None,
81 status: TransactionStatus::Pending,
82 }
83 }
84}
85
86#[derive(Clone, Debug, PartialEq, Eq)]
88pub enum TransactionStatus {
89 Pending,
90 Processing,
91 Committed,
92 Failed(TransactionError, Vec<String>),
93}
94
95impl TransactionStatus {
96 pub fn from_solana_status(
99 status: SolanaTransactionStatus,
100 logs: Vec<String>,
101 commitment: CommitmentConfig,
102 ) -> Self {
103 if let Some(TransactionError::AlreadyProcessed) = status.err {
104 TransactionStatus::Committed
105 } else if let Some(err) = status.err {
106 TransactionStatus::Failed(err, logs)
107 } else if status.satisfies_commitment(commitment) {
108 TransactionStatus::Committed
109 } else {
110 TransactionStatus::Processing
111 }
112 }
113
114 pub fn should_be_reconfirmed(&self) -> bool {
124 match self {
125 TransactionStatus::Pending => true,
126 TransactionStatus::Processing => true,
127 TransactionStatus::Committed => false,
128 TransactionStatus::Failed(..) => false,
129 }
130 }
131}
132
133impl<T> From<TransactionProgress<T>> for TransactionOutcome<T> {
134 fn from(progress: TransactionProgress<T>) -> Self {
135 match progress.status {
136 TransactionStatus::Pending | TransactionStatus::Processing => {
137 TransactionOutcome::Unknown(UnknownTransaction {
138 data: progress.data,
139 })
140 }
141 TransactionStatus::Failed(err, logs) => {
142 TransactionOutcome::Failure(FailedTransaction {
143 data: progress.data,
144 error: err.into(),
145 logs,
146 })
147 }
148 TransactionStatus::Committed => TransactionOutcome::Success(SuccessfulTransaction {
149 data: progress.data,
150 slot: progress.landed_as.unwrap().0,
151 signature: progress.landed_as.unwrap().1,
152 }),
153 }
154 }
155}