|
9 | 9 |
|
10 | 10 | use crate::instructions::{decode_instruction, InstructionContext, ParsedInstruction}; |
11 | 11 | use crate::js_obj; |
| 12 | +use crate::transaction::Transaction; |
12 | 13 | use crate::versioned::VersionedTransactionExt; |
13 | 14 | use crate::wasm::try_into_js_value::{JsConversionError, TryIntoJsValue}; |
14 | 15 | use solana_message::VersionedMessage; |
@@ -91,20 +92,52 @@ pub fn parse_transaction(bytes: &[u8]) -> Result<ParsedTransaction, String> { |
91 | 92 | { |
92 | 93 | VersionedMessage::Legacy(msg) => ( |
93 | 94 | msg.account_keys.iter().map(|k| k.to_string()).collect(), |
94 | | - &msg.instructions, |
| 95 | + &msg.instructions[..], |
95 | 96 | msg.recent_blockhash.to_string(), |
96 | 97 | msg.header.num_required_signatures, |
97 | 98 | ), |
98 | 99 | VersionedMessage::V0(msg) => ( |
99 | 100 | msg.account_keys.iter().map(|k| k.to_string()).collect(), |
100 | | - &msg.instructions, |
| 101 | + &msg.instructions[..], |
101 | 102 | msg.recent_blockhash.to_string(), |
102 | 103 | msg.header.num_required_signatures, |
103 | 104 | ), |
104 | 105 | }; |
105 | 106 |
|
106 | | - let account_keys: Vec<String> = account_keys; |
| 107 | + parse_transaction_inner( |
| 108 | + account_keys, |
| 109 | + instructions, |
| 110 | + recent_blockhash, |
| 111 | + num_required_signatures, |
| 112 | + &tx.signatures, |
| 113 | + ) |
| 114 | +} |
| 115 | + |
| 116 | +/// Parse a pre-deserialized legacy Transaction into structured data. |
| 117 | +/// |
| 118 | +/// Same logic as `parse_transaction(bytes)` but skips deserialization. |
| 119 | +/// Used when the caller already has a `Transaction` from `fromBytes()`. |
| 120 | +pub fn parse_from_transaction(tx: &Transaction) -> Result<ParsedTransaction, String> { |
| 121 | + let msg = &tx.message; |
| 122 | + let account_keys: Vec<String> = msg.account_keys.iter().map(|k| k.to_string()).collect(); |
| 123 | + |
| 124 | + parse_transaction_inner( |
| 125 | + account_keys, |
| 126 | + &msg.instructions, |
| 127 | + msg.recent_blockhash.to_string(), |
| 128 | + msg.header.num_required_signatures, |
| 129 | + &tx.signatures, |
| 130 | + ) |
| 131 | +} |
107 | 132 |
|
| 133 | +/// Shared parsing logic for both bytes-based and Transaction-based entry points. |
| 134 | +fn parse_transaction_inner( |
| 135 | + account_keys: Vec<String>, |
| 136 | + instructions: &[solana_message::compiled_instruction::CompiledInstruction], |
| 137 | + recent_blockhash: String, |
| 138 | + num_required_signatures: u8, |
| 139 | + signatures: &[solana_signature::Signature], |
| 140 | +) -> Result<ParsedTransaction, String> { |
108 | 141 | // Extract fee payer (first account key) |
109 | 142 | let fee_payer = account_keys |
110 | 143 | .first() |
@@ -156,8 +189,7 @@ pub fn parse_transaction(bytes: &[u8]) -> Result<ParsedTransaction, String> { |
156 | 189 | // Extract signatures as base58 strings. |
157 | 190 | // All-zeros signatures (unsigned placeholder slots) are returned as empty strings |
158 | 191 | // so the JS side can simply use `signatures[0] || 'UNAVAILABLE'`. |
159 | | - let signatures: Vec<String> = tx |
160 | | - .signatures |
| 192 | + let signatures: Vec<String> = signatures |
161 | 193 | .iter() |
162 | 194 | .map(|s| { |
163 | 195 | let bytes: &[u8] = s.as_ref(); |
|
0 commit comments