solana_block_decoder/message/
versioned_message.rs1use {
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 #[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 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 de::Error::invalid_length(1, &self)
157 },
158 )?))
159 }
160 127 => {
161 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}