solana_block_decoder/message/
versioned_message.rs

1use {
2    crate::{
3        message::{
4            message::Message,
5            message_v0::Message as MessageV0,
6        },
7        instruction::{
8            CompiledInstruction,
9        },
10    },
11    solana_program::{
12        short_vec,
13    },
14    solana_sdk::{
15        message::{
16            MessageHeader,
17        },
18        pubkey::{Pubkey},
19        hash::{Hash},
20    },
21    serde::{
22        de::{self, Deserializer, SeqAccess, Visitor},
23        ser::{SerializeTuple, Serializer},
24        Deserialize, Serialize,
25    },
26    std::{fmt},
27};
28
29pub const MESSAGE_VERSION_PREFIX: u8 = 0x80;
30
31#[derive(Debug, PartialEq, Eq, Clone)]
32pub enum VersionedMessage {
33    Legacy(Message),
34    V0(MessageV0),
35}
36
37impl Default for VersionedMessage {
38    fn default() -> Self {
39        Self::Legacy(Message::default())
40    }
41}
42
43impl Serialize for VersionedMessage {
44    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45    where
46        S: Serializer,
47    {
48        match self {
49            Self::Legacy(message) => {
50                let mut seq = serializer.serialize_tuple(1)?;
51                seq.serialize_element(message)?;
52                seq.end()
53            }
54            Self::V0(message) => {
55                let mut seq = serializer.serialize_tuple(2)?;
56                seq.serialize_element(&MESSAGE_VERSION_PREFIX)?;
57                seq.serialize_element(message)?;
58                seq.end()
59            }
60        }
61    }
62}
63
64enum MessagePrefix {
65    Legacy(u8),
66    Versioned(u8),
67}
68
69impl<'de> Deserialize<'de> for MessagePrefix {
70    fn deserialize<D>(deserializer: D) -> Result<MessagePrefix, D::Error>
71    where
72        D: Deserializer<'de>,
73    {
74        struct PrefixVisitor;
75
76        impl<'de> Visitor<'de> for PrefixVisitor {
77            type Value = MessagePrefix;
78
79            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80                formatter.write_str("message prefix byte")
81            }
82
83            fn visit_u8<E>(self, byte: u8) -> Result<MessagePrefix, E> {
84                if byte & MESSAGE_VERSION_PREFIX != 0 {
85                    Ok(MessagePrefix::Versioned(byte & !MESSAGE_VERSION_PREFIX))
86                } else {
87                    Ok(MessagePrefix::Legacy(byte))
88                }
89            }
90        }
91
92        deserializer.deserialize_u8(PrefixVisitor)
93    }
94}
95
96impl<'de> Deserialize<'de> for VersionedMessage {
97    fn deserialize<D>(deserializer: D) -> Result<VersionedMessage, D::Error>
98    where
99        D: Deserializer<'de>,
100    {
101        struct MessageVisitor;
102
103        impl<'de> Visitor<'de> for MessageVisitor {
104            type Value = VersionedMessage;
105
106            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
107                formatter.write_str("message bytes")
108            }
109
110            fn visit_seq<A>(self, mut seq: A) -> Result<VersionedMessage, A::Error>
111            where
112                A: SeqAccess<'de>,
113            {
114                let prefix: MessagePrefix = seq
115                    .next_element()?
116                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
117
118                match prefix {
119                    MessagePrefix::Legacy(num_required_signatures) => {
120                        // The remaining fields of the legacy Message struct after the first byte.
121                        #[derive(Serialize, Deserialize)]
122                        struct RemainingLegacyMessage {
123                            pub num_readonly_signed_accounts: u8,
124                            pub num_readonly_unsigned_accounts: u8,
125                            #[serde(with = "short_vec")]
126                            pub account_keys: Vec<Pubkey>,
127                            pub recent_blockhash: Hash,
128                            #[serde(with = "short_vec")]
129                            pub instructions: Vec<CompiledInstruction>,
130                        }
131
132                        let message: RemainingLegacyMessage =
133                            seq.next_element()?.ok_or_else(|| {
134                                // will never happen since tuple length is always 2
135                                de::Error::invalid_length(1, &self)
136                            })?;
137
138                        Ok(VersionedMessage::Legacy(Message {
139                            header: MessageHeader {
140                                num_required_signatures,
141                                num_readonly_signed_accounts: message.num_readonly_signed_accounts,
142                                num_readonly_unsigned_accounts: message
143                                    .num_readonly_unsigned_accounts,
144                            },
145                            account_keys: message.account_keys,
146                            recent_blockhash: message.recent_blockhash,
147                            instructions: message.instructions,
148                        }))
149                    }
150                    MessagePrefix::Versioned(version) => {
151                        match version {
152                            0 => {
153                                Ok(VersionedMessage::V0(seq.next_element()?.ok_or_else(
154                                    || {
155                                        // will never happen since tuple length is always 2
156                                        de::Error::invalid_length(1, &self)
157                                    },
158                                )?))
159                            }
160                            127 => {
161                                // 0xff is used as the first byte of the off-chain messages
162                                // which corresponds to version 127 of the versioned messages.
163                                // This explicit check is added to prevent the usage of version 127
164                                // in the runtime as a valid transaction.
165                                Err(de::Error::custom("off-chain messages are not accepted"))
166                            }
167                            _ => Err(de::Error::invalid_value(
168                                de::Unexpected::Unsigned(version as u64),
169                                &"a valid transaction message version",
170                            )),
171                        }
172                    }
173                }
174            }
175        }
176
177        deserializer.deserialize_tuple(2, MessageVisitor)
178    }
179}
180
181impl From<VersionedMessage> for solana_sdk::message::VersionedMessage {
182    fn from(msg: VersionedMessage) -> Self {
183        match msg {
184            VersionedMessage::Legacy(m) => solana_sdk::message::VersionedMessage::Legacy(m.into()),
185            VersionedMessage::V0(m) => solana_sdk::message::VersionedMessage::V0(m.into()),
186        }
187    }
188}