solana_block_decoder/transaction/
versioned_transaction.rs1use {
2 crate::{
3 errors::{
4 decode_error::DecodeError,
5 },
6 block::{
7 encoded_block::{
8 EncodedTransaction,
9 EncodedTransactionWithStatusMeta,
10 },
11 },
12 message::{
13 message::Message,
14 message_v0::Message as MessageV0,
15 versioned_message::VersionedMessage,
16 },
17 transaction::{
18 tx_status_meta::TransactionStatusMeta,
19 },
20 decodable::{
21 Decodable,
22 DecodableWithMeta,
23 },
24 },
25 serde::{
26 Deserialize, Serialize,
27 },
28 solana_short_vec as short_vec,
29 solana_signature::Signature,
30 solana_transaction::{
31 versioned::TransactionVersion
32 },
33 solana_transaction_status_client_types::{
34 UiMessage,
35 UiTransactionEncoding,
36 },
37 base64::{Engine, prelude::BASE64_STANDARD},
38};
39
40#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
41pub struct VersionedTransactionWithStatusMeta {
42 pub transaction: VersionedTransaction,
43 pub meta: TransactionStatusMeta,
44}
45
46impl VersionedTransactionWithStatusMeta {
47 pub fn decode(
48 encoded: EncodedTransactionWithStatusMeta,
49 encoding: UiTransactionEncoding,
50 ) -> Result<Self, DecodeError> {
51 let transaction = match VersionedTransaction::decode_with_meta(encoded.transaction, encoding, encoded.version ) {
53 Ok(decoded) => decoded,
54 Err(e) => return Err(e),
55 };
56
57 let meta = match encoded.meta {
59 Some(ui_meta) => match TransactionStatusMeta::try_from(ui_meta) {
60 Ok(meta) => meta,
61 Err(_) => return Err(DecodeError::InvalidData),
62 },
63 None => return Err(DecodeError::InvalidData),
64 };
65
66 Ok(Self {
67 transaction,
68 meta,
69 })
70 }
71}
72
73#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)]
74pub struct VersionedTransaction {
75 #[serde(with = "short_vec")]
77 pub signatures: Vec<Signature>,
78 pub message: VersionedMessage,
80}
81
82
83impl DecodableWithMeta for VersionedTransaction {
84 type Encoded = EncodedTransaction;
85 type Decoded = VersionedTransaction;
86
87 fn decode_with_meta(
88 encoded: Self::Encoded,
89 decoding: UiTransactionEncoding,
90 version: Option<TransactionVersion>
91 ) -> Result<Self::Decoded, DecodeError> {
92 match decoding {
93 UiTransactionEncoding::Binary | UiTransactionEncoding::Base58 => {
94 if let EncodedTransaction::LegacyBinary(encoded_string) = encoded {
95 let decoded_bytes = bs58::decode(encoded_string).into_vec().unwrap();
96 let decoded: Self::Decoded =
97 bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
98 Ok(decoded)
99 } else {
100 Err(DecodeError::UnsupportedEncoding)
101 }
102 }
103 UiTransactionEncoding::Base64 => {
104 if let EncodedTransaction::Binary(encoded_string, _) = encoded {
105 let decoded_bytes = BASE64_STANDARD.decode(encoded_string).unwrap();
106 let decoded: Self::Decoded =
107 bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
108 Ok(decoded)
109 } else {
110 Err(DecodeError::UnsupportedEncoding)
111 }
112 }
113 UiTransactionEncoding::Json => Self::json_decode(encoded, version),
114 UiTransactionEncoding::JsonParsed => Err(DecodeError::UnsupportedEncoding),
115 }
116 }
117
118 fn json_decode(encoded: Self::Encoded, version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError> {
119 if let EncodedTransaction::Json(ui_transaction) = encoded {
120 let signatures = ui_transaction
121 .signatures
122 .iter()
123 .map(|s| s.parse::<Signature>())
124 .collect::<Result<Vec<_>, _>>()
125 .map_err(|err| DecodeError::ParseSignatureFailed(err))?;
126
127 let message = match ui_transaction.message {
128 UiMessage::Raw(_) => {
129 match version {
130 Some(TransactionVersion::Number(0)) => {
131 let v0_message = MessageV0::json_decode(ui_transaction.message, version)?;
133 VersionedMessage::V0(v0_message)
134 }
135 Some(TransactionVersion::Legacy(_)) | None => {
136 let legacy_message = Message::decode(&ui_transaction.message)?;
138 VersionedMessage::Legacy(legacy_message)
139 }
140 _ => {
142 return Err(DecodeError::UnsupportedVersion);
144 }
145 }
146 }
147 UiMessage::Parsed(_) => {
148 return Err(DecodeError::UnsupportedEncoding);
149 }
150 };
151
152 Ok(Self {
153 signatures,
154 message,
155 })
156 } else {
157 Err(DecodeError::UnsupportedEncoding)
158 }
159 }
160}
161
162impl From<VersionedTransaction> for solana_transaction::versioned::VersionedTransaction {
163 fn from(tx: VersionedTransaction) -> Self {
164 Self {
165 signatures: tx.signatures,
166 message: tx.message.into(),
167 }
168 }
169}
170
171impl From<VersionedTransactionWithStatusMeta> for solana_transaction_status::VersionedTransactionWithStatusMeta {
172 fn from(tx: VersionedTransactionWithStatusMeta) -> Self {
173 Self {
174 transaction: tx.transaction.into(),
175 meta: tx.meta.into(),
176 }
177 }
178}