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_program::short_vec,
29 solana_sdk::{
30 signature::Signature,
31 transaction::TransactionVersion,
32 },
33 solana_transaction_status::{
34 UiMessage,
35 UiTransactionEncoding,
36 },
37};
38
39#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
40pub struct VersionedTransactionWithStatusMeta {
41 pub transaction: VersionedTransaction,
42 pub meta: TransactionStatusMeta,
43}
44
45impl VersionedTransactionWithStatusMeta {
46 pub fn decode(
47 encoded: EncodedTransactionWithStatusMeta,
48 encoding: UiTransactionEncoding,
49 ) -> Result<Self, DecodeError> {
50 let transaction = match VersionedTransaction::decode_with_meta(encoded.transaction, encoding, encoded.version ) {
52 Ok(decoded) => decoded,
53 Err(e) => return Err(e),
54 };
55
56 let meta = match encoded.meta {
58 Some(ui_meta) => match TransactionStatusMeta::try_from(ui_meta) {
59 Ok(meta) => meta,
60 Err(_) => return Err(DecodeError::InvalidData),
61 },
62 None => return Err(DecodeError::InvalidData),
63 };
64
65 Ok(Self {
66 transaction,
67 meta,
68 })
69 }
70}
71
72#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)]
73pub struct VersionedTransaction {
74 #[serde(with = "short_vec")]
76 pub signatures: Vec<Signature>,
77 pub message: VersionedMessage,
79}
80
81
82impl DecodableWithMeta for VersionedTransaction {
83 type Encoded = EncodedTransaction;
84 type Decoded = VersionedTransaction;
85
86 fn decode_with_meta(
87 encoded: Self::Encoded,
88 decoding: UiTransactionEncoding,
89 version: Option<TransactionVersion>
90 ) -> Result<Self::Decoded, DecodeError> {
91 match decoding {
92 UiTransactionEncoding::Binary | UiTransactionEncoding::Base58 => {
93 if let EncodedTransaction::LegacyBinary(encoded_string) = encoded {
94 let decoded_bytes = bs58::decode(encoded_string).into_vec().unwrap();
95 let decoded: Self::Decoded =
96 bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
97 Ok(decoded)
98 } else {
99 Err(DecodeError::UnsupportedEncoding)
100 }
101 }
102 UiTransactionEncoding::Base64 => {
103 if let EncodedTransaction::Binary(encoded_string, _) = encoded {
104 let decoded_bytes = base64::decode(encoded_string).unwrap();
105 let decoded: Self::Decoded =
106 bincode::deserialize(&decoded_bytes).map_err(|_| DecodeError::DeserializeFailed)?;
107 Ok(decoded)
108 } else {
109 Err(DecodeError::UnsupportedEncoding)
110 }
111 }
112 UiTransactionEncoding::Json => Self::json_decode(encoded, version),
113 UiTransactionEncoding::JsonParsed => Err(DecodeError::UnsupportedEncoding),
114 }
115 }
116
117 fn json_decode(encoded: Self::Encoded, version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError> {
118 if let EncodedTransaction::Json(ui_transaction) = encoded {
119 let signatures = ui_transaction
120 .signatures
121 .iter()
122 .map(|s| s.parse::<Signature>())
123 .collect::<Result<Vec<_>, _>>()
124 .map_err(|err| DecodeError::ParseSignatureFailed(err))?;
125
126 let message = match ui_transaction.message {
127 UiMessage::Raw(_) => {
128 match version {
129 Some(TransactionVersion::Number(0)) => {
130 let v0_message = MessageV0::json_decode(ui_transaction.message, version)?;
132 VersionedMessage::V0(v0_message)
133 }
134 Some(TransactionVersion::Legacy(_)) | None => {
135 let legacy_message = Message::decode(&ui_transaction.message)?;
137 VersionedMessage::Legacy(legacy_message)
138 }
139 _ => {
141 return Err(DecodeError::UnsupportedVersion);
143 }
144 }
145 }
146 UiMessage::Parsed(_) => {
147 return Err(DecodeError::UnsupportedEncoding);
148 }
149 };
150
151 Ok(Self {
152 signatures,
153 message,
154 })
155 } else {
156 Err(DecodeError::UnsupportedEncoding)
157 }
158 }
159}
160
161impl From<VersionedTransaction> for solana_sdk::transaction::VersionedTransaction {
162 fn from(tx: VersionedTransaction) -> Self {
163 Self {
164 signatures: tx.signatures,
165 message: tx.message.into(),
166 }
167 }
168}
169
170impl From<VersionedTransactionWithStatusMeta> for solana_transaction_status::VersionedTransactionWithStatusMeta {
171 fn from(tx: VersionedTransactionWithStatusMeta) -> Self {
172 Self {
173 transaction: tx.transaction.into(),
174 meta: tx.meta.into(),
175 }
176 }
177}