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 @@ -609,6 +609,14 @@ impl<O: AbiEnumVisitor, E: AbiEnumVisitor> AbiEnumVisitor for Result<O, E> {
}
}

impl AbiEnumVisitor for str {
fn visit_for_abi(&self, digester: &mut AbiDigester) -> DigestResult {
println!("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
199 changes: 166 additions & 33 deletions message/src/versions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub const MESSAGE_VERSION_PREFIX: u8 = 0x80;
/// format.
#[cfg_attr(
feature = "frozen-abi",
frozen_abi(digest = "6CoVPUxkUvDrAvAkfyVXwVDHCSf77aufm7DEZy5mBVeX"),
frozen_abi(digest = "AhtHE2kgteii32oVSM2cMtmKx29AZPR5fqekfBfDvxNd"),
derive(AbiEnumVisitor, AbiExample)
)]
#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -207,25 +207,46 @@ 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()
}
Self::V0(message) => {
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&MESSAGE_VERSION_PREFIX)?;
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 },
#[serde(rename = "1")]
V1 { message: &'a v1::Message },
}
Self::V1(message) => {
// Note that this format does not match the wire format per SIMD-0385.

let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&crate::v1::V1_PREFIX)?;
seq.serialize_element(message)?;
seq.end()
let hr = match self {
Self::Legacy(message) => HR::Legacy { message },
Self::V0(message) => HR::V0 { message },
Self::V1(message) => HR::V1 { 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()
}
Self::V1(message) => {
// Note that this format does not match the wire format per SIMD-0385.

let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&crate::v1::V1_PREFIX)?;
seq.serialize_element(message)?;
seq.end()
}
}
}
}
Expand Down Expand Up @@ -281,7 +302,6 @@ impl<'de> serde::Deserialize<'de> for VersionedMessage {
D: Deserializer<'de>,
{
struct MessageVisitor;

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

Expand All @@ -296,7 +316,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 @@ -364,7 +383,26 @@ 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 },
Comment thread
jstarry marked this conversation as resolved.
#[serde(rename = "1")]
V1 { message: v1::Message },
}

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

Expand Down Expand Up @@ -486,7 +524,10 @@ unsafe impl<'de, C: Config> SchemaRead<'de, C> for VersionedMessage {
mod tests {
use {
super::*,
crate::{v0::MessageAddressTableLookup, v1::V1_PREFIX},
crate::{
v0::MessageAddressTableLookup,
v1::{TransactionConfig, V1_PREFIX},
},
proptest::{
collection::vec,
option::of,
Expand All @@ -511,6 +552,27 @@ mod tests {
data: Vec<u8>,
}

#[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);

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

#[test]
fn test_legacy_message_serialization() {
let program_id0 = Address::new_unique();
Expand Down Expand Up @@ -544,10 +606,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 @@ -556,12 +618,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 {
fn test_v0_message_serialization() {
let message = v0::Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
Expand All @@ -586,15 +653,81 @@ mod tests {
accounts: vec![0, 2, 3, 4],
data: vec![],
}],
});
};
let wrapped_message = VersionedMessage::V0(message.clone());

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

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);
}
}

#[test]
fn test_v1_message_serialization() {
let message = v1::Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
num_readonly_unsigned_accounts: 0,
},
config: TransactionConfig {
priority_fee: Some(1000),
compute_unit_limit: Some(200_000),
loaded_accounts_data_size_limit: Some(10_000),
heap_size: Some(65536),
},
lifetime_specifier: Hash::new_unique(),
account_keys: vec![Address::new_unique()],
instructions: vec![CompiledInstruction {
program_id_index: 1,
accounts: vec![0, 2, 3, 4],
data: vec![],
}],
};
let wrapped_message = VersionedMessage::V1(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: v1::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: v1::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);
}
}

prop_compose! {
Expand Down