gemachain_program/message/
versions.rs

1use {
2    crate::{
3        hash::Hash,
4        instruction::CompiledInstruction,
5        message::{v0, Message, MessageHeader},
6        pubkey::Pubkey,
7        sanitize::{Sanitize, SanitizeError},
8        short_vec,
9    },
10    serde::{
11        de::{self, Deserializer, SeqAccess, Visitor},
12        ser::{SerializeTuple, Serializer},
13        {Deserialize, Serialize},
14    },
15    std::fmt,
16};
17
18/// Bit mask that indicates whether a serialized message is versioned.
19pub const MESSAGE_VERSION_PREFIX: u8 = 0x80;
20
21/// Message versions supported by the Gemachain runtime.
22///
23/// # Serialization
24///
25/// If the first bit is set, the remaining 7 bits will be used to determine
26/// which message version is serialized starting from version `0`. If the first
27/// is bit is not set, all bytes are used to encode the legacy `Message`
28/// format.
29#[frozen_abi(digest = "qKNCqQpsBZYQxS9P3hVcFr8hAF4VnqV6ZBdC6KoUvHJ")]
30#[derive(Debug, PartialEq, Eq, Clone, AbiEnumVisitor, AbiExample)]
31pub enum VersionedMessage {
32    Legacy(Message),
33    V0(v0::Message),
34}
35
36impl VersionedMessage {
37    pub fn header(&self) -> &MessageHeader {
38        match self {
39            Self::Legacy(message) => &message.header,
40            Self::V0(message) => &message.header,
41        }
42    }
43
44    pub fn unmapped_keys(self) -> Vec<Pubkey> {
45        match self {
46            Self::Legacy(message) => message.account_keys,
47            Self::V0(message) => message.account_keys,
48        }
49    }
50
51    pub fn unmapped_keys_iter(&self) -> impl Iterator<Item = &Pubkey> {
52        match self {
53            Self::Legacy(message) => message.account_keys.iter(),
54            Self::V0(message) => message.account_keys.iter(),
55        }
56    }
57
58    pub fn unmapped_keys_len(&self) -> usize {
59        match self {
60            Self::Legacy(message) => message.account_keys.len(),
61            Self::V0(message) => message.account_keys.len(),
62        }
63    }
64
65    pub fn recent_blockhash(&self) -> &Hash {
66        match self {
67            Self::Legacy(message) => &message.recent_blockhash,
68            Self::V0(message) => &message.recent_blockhash,
69        }
70    }
71
72    pub fn set_recent_blockhash(&mut self, recent_blockhash: Hash) {
73        match self {
74            Self::Legacy(message) => message.recent_blockhash = recent_blockhash,
75            Self::V0(message) => message.recent_blockhash = recent_blockhash,
76        }
77    }
78
79    pub fn serialize(&self) -> Vec<u8> {
80        bincode::serialize(self).unwrap()
81    }
82
83    /// Compute the blake3 hash of this transaction's message
84    pub fn hash(&self) -> Hash {
85        let message_bytes = self.serialize();
86        Self::hash_raw_message(&message_bytes)
87    }
88
89    /// Compute the blake3 hash of a raw transaction message
90    pub fn hash_raw_message(message_bytes: &[u8]) -> Hash {
91        use blake3::traits::digest::Digest;
92        use std::convert::TryFrom;
93        let mut hasher = blake3::Hasher::new();
94        hasher.update(b"gemachain-tx-message-v1");
95        hasher.update(message_bytes);
96        Hash(<[u8; crate::hash::HASH_BYTES]>::try_from(hasher.finalize().as_slice()).unwrap())
97    }
98}
99
100impl Default for VersionedMessage {
101    fn default() -> Self {
102        Self::Legacy(Message::default())
103    }
104}
105
106impl Sanitize for VersionedMessage {
107    fn sanitize(&self) -> Result<(), SanitizeError> {
108        match self {
109            Self::Legacy(message) => message.sanitize(),
110            Self::V0(message) => message.sanitize(),
111        }
112    }
113}
114
115impl Serialize for VersionedMessage {
116    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: Serializer,
119    {
120        match self {
121            Self::Legacy(message) => {
122                let mut seq = serializer.serialize_tuple(1)?;
123                seq.serialize_element(message)?;
124                seq.end()
125            }
126            Self::V0(message) => {
127                let mut seq = serializer.serialize_tuple(2)?;
128                seq.serialize_element(&MESSAGE_VERSION_PREFIX)?;
129                seq.serialize_element(message)?;
130                seq.end()
131            }
132        }
133    }
134}
135
136enum MessagePrefix {
137    Legacy(u8),
138    Versioned(u8),
139}
140
141impl<'de> Deserialize<'de> for MessagePrefix {
142    fn deserialize<D>(deserializer: D) -> Result<MessagePrefix, D::Error>
143    where
144        D: Deserializer<'de>,
145    {
146        struct PrefixVisitor;
147
148        impl<'de> Visitor<'de> for PrefixVisitor {
149            type Value = MessagePrefix;
150
151            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
152                formatter.write_str("message prefix byte")
153            }
154
155            fn visit_u8<E>(self, byte: u8) -> Result<MessagePrefix, E> {
156                if byte & MESSAGE_VERSION_PREFIX != 0 {
157                    Ok(MessagePrefix::Versioned(byte & !MESSAGE_VERSION_PREFIX))
158                } else {
159                    Ok(MessagePrefix::Legacy(byte))
160                }
161            }
162        }
163
164        deserializer.deserialize_u8(PrefixVisitor)
165    }
166}
167
168impl<'de> Deserialize<'de> for VersionedMessage {
169    fn deserialize<D>(deserializer: D) -> Result<VersionedMessage, D::Error>
170    where
171        D: Deserializer<'de>,
172    {
173        struct MessageVisitor;
174
175        impl<'de> Visitor<'de> for MessageVisitor {
176            type Value = VersionedMessage;
177
178            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
179                formatter.write_str("message bytes")
180            }
181
182            fn visit_seq<A>(self, mut seq: A) -> Result<VersionedMessage, A::Error>
183            where
184                A: SeqAccess<'de>,
185            {
186                let prefix: MessagePrefix = seq
187                    .next_element()?
188                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
189
190                match prefix {
191                    MessagePrefix::Legacy(num_required_signatures) => {
192                        // The remaining fields of the legacy Message struct after the first byte.
193                        #[derive(Serialize, Deserialize)]
194                        struct RemainingLegacyMessage {
195                            pub num_readonly_signed_accounts: u8,
196                            pub num_readonly_unsigned_accounts: u8,
197                            #[serde(with = "short_vec")]
198                            pub account_keys: Vec<Pubkey>,
199                            pub recent_blockhash: Hash,
200                            #[serde(with = "short_vec")]
201                            pub instructions: Vec<CompiledInstruction>,
202                        }
203
204                        let message: RemainingLegacyMessage =
205                            seq.next_element()?.ok_or_else(|| {
206                                // will never happen since tuple length is always 2
207                                de::Error::invalid_length(1, &self)
208                            })?;
209
210                        Ok(VersionedMessage::Legacy(Message {
211                            header: MessageHeader {
212                                num_required_signatures,
213                                num_readonly_signed_accounts: message.num_readonly_signed_accounts,
214                                num_readonly_unsigned_accounts: message
215                                    .num_readonly_unsigned_accounts,
216                            },
217                            account_keys: message.account_keys,
218                            recent_blockhash: message.recent_blockhash,
219                            instructions: message.instructions,
220                        }))
221                    }
222                    MessagePrefix::Versioned(version) => {
223                        if version == 0 {
224                            Ok(VersionedMessage::V0(seq.next_element()?.ok_or_else(
225                                || {
226                                    // will never happen since tuple length is always 2
227                                    de::Error::invalid_length(1, &self)
228                                },
229                            )?))
230                        } else {
231                            Err(de::Error::invalid_value(
232                                de::Unexpected::Unsigned(version as u64),
233                                &"supported versions: [0]",
234                            ))
235                        }
236                    }
237                }
238            }
239        }
240
241        deserializer.deserialize_tuple(2, MessageVisitor)
242    }
243}
244
245#[cfg(test)]
246mod tests {
247    use super::*;
248    use crate::{
249        instruction::{AccountMeta, Instruction},
250        message::v0::AddressMapIndexes,
251    };
252
253    #[test]
254    fn test_legacy_message_serialization() {
255        let program_id0 = Pubkey::new_unique();
256        let program_id1 = Pubkey::new_unique();
257        let id0 = Pubkey::new_unique();
258        let id1 = Pubkey::new_unique();
259        let id2 = Pubkey::new_unique();
260        let id3 = Pubkey::new_unique();
261        let instructions = vec![
262            Instruction::new_with_bincode(program_id0, &0, vec![AccountMeta::new(id0, false)]),
263            Instruction::new_with_bincode(program_id0, &0, vec![AccountMeta::new(id1, true)]),
264            Instruction::new_with_bincode(
265                program_id1,
266                &0,
267                vec![AccountMeta::new_readonly(id2, false)],
268            ),
269            Instruction::new_with_bincode(
270                program_id1,
271                &0,
272                vec![AccountMeta::new_readonly(id3, true)],
273            ),
274        ];
275
276        let mut message = Message::new(&instructions, Some(&id1));
277        message.recent_blockhash = Hash::new_unique();
278
279        let bytes1 = bincode::serialize(&message).unwrap();
280        let bytes2 = bincode::serialize(&VersionedMessage::Legacy(message.clone())).unwrap();
281
282        assert_eq!(bytes1, bytes2);
283
284        let message1: Message = bincode::deserialize(&bytes1).unwrap();
285        let message2: VersionedMessage = bincode::deserialize(&bytes2).unwrap();
286
287        if let VersionedMessage::Legacy(message2) = message2 {
288            assert_eq!(message, message1);
289            assert_eq!(message1, message2);
290        } else {
291            panic!("should deserialize to legacy message");
292        }
293    }
294
295    #[test]
296    fn test_versioned_message_serialization() {
297        let message = v0::Message {
298            header: MessageHeader {
299                num_required_signatures: 1,
300                num_readonly_signed_accounts: 0,
301                num_readonly_unsigned_accounts: 2,
302            },
303            recent_blockhash: Hash::new_unique(),
304            account_keys: vec![
305                Pubkey::new_unique(),
306                Pubkey::new_unique(),
307                Pubkey::new_unique(),
308            ],
309            address_map_indexes: vec![
310                AddressMapIndexes {
311                    writable: vec![1],
312                    readonly: vec![0],
313                },
314                AddressMapIndexes {
315                    writable: vec![0],
316                    readonly: vec![1],
317                },
318            ],
319            instructions: vec![CompiledInstruction {
320                program_id_index: 1,
321                accounts: vec![0],
322                data: vec![],
323            }],
324        };
325
326        let bytes = bincode::serialize(&VersionedMessage::V0(message.clone())).unwrap();
327        let message_from_bytes: VersionedMessage = bincode::deserialize(&bytes).unwrap();
328
329        if let VersionedMessage::V0(message_from_bytes) = message_from_bytes {
330            assert_eq!(message, message_from_bytes);
331        } else {
332            panic!("should deserialize to versioned message");
333        }
334    }
335}