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