solana_block_decoder/message/
message_v0.rs

1use {
2    crate::{
3        address::{
4            address_table_lookup::MessageAddressTableLookup,
5        },
6        errors::{
7            decode_error::DecodeError,
8        },
9        instruction::{
10            CompiledInstruction,
11        },
12        decodable::{
13            DecodableWithMeta,
14        },
15    },
16    serde_derive::{Deserialize, Serialize},
17    solana_program::short_vec,
18    solana_sdk::{
19        hash::Hash,
20        message::{
21            v0::Message as SolanaMessageV0,
22            MessageHeader,
23        },
24        pubkey::Pubkey,
25        transaction::TransactionVersion,
26    },
27    solana_transaction_status::{
28        UiMessage,
29        UiTransactionEncoding,
30    },
31};
32
33#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)]
34#[serde(rename_all = "camelCase")]
35pub struct Message {
36    /// The message header, identifying signed and read-only `account_keys`.
37    /// Header values only describe static `account_keys`, they do not describe
38    /// any additional account keys loaded via address table lookups.
39    pub header: MessageHeader,
40
41    /// List of accounts loaded by this transaction.
42    #[serde(with = "short_vec")]
43    pub account_keys: Vec<Pubkey>,
44
45    /// The blockhash of a recent block.
46    pub recent_blockhash: Hash,
47
48    /// Instructions that invoke a designated program, are executed in sequence,
49    /// and committed in one atomic transaction if all succeed.
50    ///
51    /// # Notes
52    ///
53    /// Program indexes must index into the list of message `account_keys` because
54    /// program id's cannot be dynamically loaded from a lookup table.
55    ///
56    /// Account indexes must index into the list of addresses
57    /// constructed from the concatenation of three key lists:
58    ///   1) message `account_keys`
59    ///   2) ordered list of keys loaded from `writable` lookup table indexes
60    ///   3) ordered list of keys loaded from `readable` lookup table indexes
61    #[serde(with = "short_vec")]
62    pub instructions: Vec<CompiledInstruction>,
63
64    /// List of address table lookups used to load additional accounts
65    /// for this transaction.
66    #[serde(with = "short_vec")]
67    pub address_table_lookups: Vec<MessageAddressTableLookup>,
68}
69
70impl DecodableWithMeta for Message {
71    type Encoded = UiMessage;
72    type Decoded = Message;
73
74    fn decode_with_meta(
75        encoded: Self::Encoded,
76        decoding: UiTransactionEncoding,
77        version: Option<TransactionVersion>
78    ) -> Result<Self::Decoded, DecodeError> {
79        match decoding {
80            UiTransactionEncoding::Json => match encoded {
81                UiMessage::Raw(_) => Self::json_decode(encoded, version),
82                UiMessage::Parsed(_) => Err(DecodeError::UnsupportedEncoding),
83            },
84            _ => Err(DecodeError::UnsupportedEncoding),
85        }
86    }
87
88    fn json_decode(encoded: Self::Encoded, _version: Option<TransactionVersion>) -> Result<Self::Decoded, DecodeError> {
89        if let UiMessage::Raw(raw_msg) = encoded {
90            let header = raw_msg.header;
91            let account_keys = raw_msg.account_keys
92                .iter()
93                .map(|s| s.parse::<Pubkey>())
94                .collect::<Result<Vec<_>, _>>()
95                .map_err(|_| DecodeError::InvalidAccountKey)?;
96            let recent_blockhash = raw_msg.recent_blockhash.parse::<Hash>()
97                .map_err(|_| DecodeError::InvalidBlockhash)?;
98            let instructions = raw_msg.instructions
99                .iter()
100                .map(|i| CompiledInstruction::from(i.clone()))
101                .collect::<Vec<_>>();
102            let address_table_lookups = match raw_msg.address_table_lookups {
103                Some(lookups) => lookups
104                    .iter()
105                    .map(|lookup| MessageAddressTableLookup::try_from(lookup).unwrap())
106                    .collect(),
107                None => vec![],
108            };
109
110            Ok(Self {
111                header,
112                account_keys,
113                recent_blockhash,
114                instructions,
115                address_table_lookups,
116            })
117        } else {
118            Err(DecodeError::UnsupportedEncoding)
119        }
120    }
121}
122
123
124impl From<Message> for SolanaMessageV0 {
125    fn from(msg: Message) -> Self {
126        Self {
127            header: msg.header,
128            account_keys: msg.account_keys,
129            recent_blockhash: msg.recent_blockhash,
130            instructions: msg.instructions.into_iter().map(Into::into).collect(),
131            address_table_lookups: msg.address_table_lookups.into_iter().map(Into::into).collect(),
132        }
133    }
134}