Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions frozen-abi/src/abi_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,14 @@ impl<O: AbiEnumVisitor, E: AbiEnumVisitor> AbiEnumVisitor for Result<O, E> {
}
}

impl AbiEnumVisitor for str {
fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
info!("AbiEnumVisitor for str");
"".serialize(digester.create_new())
.map_err(DigestError::wrap_by_type::<str>)
}
}

#[cfg(not(target_os = "solana"))]
impl<T: AbiExample> AbiExample for std::sync::OnceLock<T> {
fn example() -> Self {
Expand Down
117 changes: 93 additions & 24 deletions message/src/versions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub const MESSAGE_VERSION_PREFIX: u8 = 0x80;
/// format.
#[cfg_attr(
feature = "frozen-abi",
frozen_abi(digest = "Hndd1SDxQ5qNZvzHo77dpW6uD5c1DJNVjtg8tE6hc432"),
frozen_abi(digest = "AbhbWKcm8BEickDjeXN7mL4BTvrqvhVKv7ZXNykq22ck"),
derive(AbiEnumVisitor, AbiExample)
)]
#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -181,17 +181,35 @@ impl serde::Serialize for VersionedMessage {
where
S: Serializer,
{
match self {
Self::Legacy(message) => {
let mut seq = serializer.serialize_tuple(1)?;
seq.serialize_element(message)?;
seq.end()
if serializer.is_human_readable() {
#[derive(Serialize)]
#[serde(tag = "version")]
enum HR<'a> {
#[serde(rename = "legacy")]
Legacy { message: &'a LegacyMessage },
#[serde(rename = "0")]
V0 { message: &'a v0::Message },
}
Self::V0(message) => {
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&MESSAGE_VERSION_PREFIX)?;
seq.serialize_element(message)?;
seq.end()

let hr = match self {
Self::Legacy(message) => HR::Legacy { message },
Self::V0(message) => HR::V0 { message },
};

HR::serialize(&hr, serializer)
} else {
match self {
Self::Legacy(message) => {
let mut seq = serializer.serialize_tuple(1)?;
seq.serialize_element(message)?;
seq.end()
}
Self::V0(message) => {
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&MESSAGE_VERSION_PREFIX)?;
seq.serialize_element(message)?;
seq.end()
}
}
}
}
Expand Down Expand Up @@ -247,7 +265,6 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage {
D: Deserializer<'de>,
{
struct MessageVisitor;

impl<'de> Visitor<'de> for MessageVisitor {
type Value = VersionedMessage;

Expand All @@ -262,7 +279,6 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage {
let prefix: MessagePrefix = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;

match prefix {
MessagePrefix::Legacy(num_required_signatures) => {
// The remaining fields of the legacy Message struct after the first byte.
Expand Down Expand Up @@ -322,7 +338,23 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage {
}
}

deserializer.deserialize_tuple(2, MessageVisitor)
if deserializer.is_human_readable() {
#[derive(Deserialize)]
#[serde(tag = "version")]
enum HR {
#[serde(rename = "legacy")]
Legacy { message: LegacyMessage },
#[serde(rename = "0")]
V0 { message: v0::Message },
}

match HR::deserialize(deserializer)? {
HR::Legacy { message } => Ok(VersionedMessage::Legacy(message)),
HR::V0 { message } => Ok(VersionedMessage::V0(message)),
}
} else {
deserializer.deserialize_tuple(2, MessageVisitor)
}
}
}

Expand All @@ -334,6 +366,21 @@ mod tests {
solana_instruction::{AccountMeta, Instruction},
};

#[test]
fn test_versioned_message_human_readable_serialization() {
let message = LegacyMessage::default();
let message_string = serde_json::to_string(&message).unwrap();
let string = serde_json::to_string(&VersionedMessage::Legacy(message)).unwrap();
let expected_string = format!(r#"{{"version":"legacy","message":{message_string}}}"#);
assert_eq!(string, expected_string);

let message = v0::Message::default();
let message_string = serde_json::to_string(&message).unwrap();
let string = serde_json::to_string(&VersionedMessage::V0(message)).unwrap();
let expected_string = format!(r#"{{"version":"0","message":{message_string}}}"#);
assert_eq!(string, expected_string);
}

#[test]
fn test_legacy_message_serialization() {
let program_id0 = Address::new_unique();
Expand Down Expand Up @@ -367,10 +414,10 @@ mod tests {
assert_eq!(bytes, bincode::serialize(&wrapped_message).unwrap());

let message_from_bytes: LegacyMessage = bincode::deserialize(&bytes).unwrap();
assert_eq!(message, message_from_bytes);

let wrapped_message_from_bytes: VersionedMessage =
bincode::deserialize(&bytes).unwrap();

assert_eq!(message, message_from_bytes);
assert_eq!(wrapped_message, wrapped_message_from_bytes);
}

Expand All @@ -379,12 +426,17 @@ mod tests {
let string = serde_json::to_string(&message).unwrap();
let message_from_string: LegacyMessage = serde_json::from_str(&string).unwrap();
assert_eq!(message, message_from_string);

let wrapped_string = serde_json::to_string(&wrapped_message).unwrap();
let wrapped_message_from_string: VersionedMessage =
serde_json::from_str(&wrapped_string).unwrap();
assert_eq!(wrapped_message, wrapped_message_from_string);
}
}

#[test]
fn test_versioned_message_serialization() {
let message = VersionedMessage::V0(v0::Message {
let message = v0::Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
Expand All @@ -409,14 +461,31 @@ mod tests {
accounts: vec![0, 2, 3, 4],
data: vec![],
}],
});
};
let wrapped_message = VersionedMessage::V0(message.clone());

let bytes = bincode::serialize(&message).unwrap();
let message_from_bytes: VersionedMessage = bincode::deserialize(&bytes).unwrap();
assert_eq!(message, message_from_bytes);
// bincode
{
let bytes = bincode::serialize(&message).unwrap();
let message_from_bytes: v0::Message = bincode::deserialize(&bytes).unwrap();
assert_eq!(message, message_from_bytes);

let string = serde_json::to_string(&message).unwrap();
let message_from_string: VersionedMessage = serde_json::from_str(&string).unwrap();
assert_eq!(message, message_from_string);
let wrapped_bytes = bincode::serialize(&wrapped_message).unwrap();
let wrapped_message_from_bytes: VersionedMessage =
bincode::deserialize(&wrapped_bytes).unwrap();
assert_eq!(wrapped_message, wrapped_message_from_bytes);
}

// serde_json
{
let string = serde_json::to_string(&message).unwrap();
let message_from_string: v0::Message = serde_json::from_str(&string).unwrap();
assert_eq!(message, message_from_string);

let wrapped_string = serde_json::to_string(&wrapped_message).unwrap();
let wrapped_message_from_string: VersionedMessage =
serde_json::from_str(&wrapped_string).unwrap();
assert_eq!(wrapped_message, wrapped_message_from_string);
}
}
}