Skip to content
Draft
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
2 changes: 1 addition & 1 deletion message/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn compile_instructions(ixs: &[Instruction], keys: &[Address]) -> Vec<CompiledIn
// for versioned messages in the `RemainingLegacyMessage` struct.
#[cfg_attr(
feature = "frozen-abi",
frozen_abi(digest = "GXpvLNiMCnjnZpQEDKpc2NBpsqmRnAX7ZTCy9JmvG8Dg"),
frozen_abi(digest = "AhkTFHhRftw61EGDjZcMZhoLozeSnb1gRRZmQeoaPXeE"),
derive(AbiExample)
)]
#[cfg_attr(
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 = "7yd5QJuxKgmkEt2ig4X91pCJCfTtjZVarMSzJ4eWzBrE"),
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);
}
}
}
8 changes: 6 additions & 2 deletions message/src/versions/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use loaded::*;
#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "frozen-abi")]
use solana_frozen_abi_macro::AbiExample;
use solana_frozen_abi_macro::{frozen_abi, AbiExample};
use {
crate::{
compiled_instruction::CompiledInstruction,
Expand Down Expand Up @@ -57,7 +57,11 @@ pub struct MessageAddressTableLookup {
///
/// See the crate documentation for further description.
///
#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
#[cfg_attr(
feature = "frozen-abi",
frozen_abi(digest = "4Mr6qK8Srdgr7PyeZjXy99ekj5pwHQSbNCVD3TmzcxTM"),
derive(AbiExample)
)]
#[cfg_attr(
feature = "serde",
derive(Deserialize, Serialize),
Expand Down
64 changes: 56 additions & 8 deletions short-vec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ impl Serialize for ShortU16 {
where
S: Serializer,
{
if serializer.is_human_readable() {
return serializer.serialize_u16(self.0);
}

// Pass a non-zero value to serialize_tuple() so that serde_json will
// generate an open bracket.
let mut seq = serializer.serialize_tuple(1)?;
Expand Down Expand Up @@ -155,7 +159,11 @@ impl<'de> Deserialize<'de> for ShortU16 {
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple(3, ShortU16Visitor)
if deserializer.is_human_readable() {
Ok(ShortU16(u16::deserialize(deserializer)?))
} else {
deserializer.deserialize_tuple(3, ShortU16Visitor)
}
}
}

Expand All @@ -168,6 +176,15 @@ pub fn serialize<S: Serializer, T: Serialize>(
elements: &[T],
serializer: S,
) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
use serde_core::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(elements.len()))?;
for element in elements {
seq.serialize_element(element)?;
}
return seq.end();
}

// Pass a non-zero value to serialize_tuple() so that serde_json will
// generate an open bracket.
let mut seq = serializer.serialize_tuple(1)?;
Expand Down Expand Up @@ -229,6 +246,9 @@ where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
if deserializer.is_human_readable() {
return <Vec<T> as Deserialize<'de>>::deserialize(deserializer);
}
let visitor = ShortVecVisitor { _t: PhantomData };
deserializer.deserialize_tuple(usize::MAX, visitor)
}
Expand Down Expand Up @@ -274,8 +294,43 @@ mod tests {
super::*,
assert_matches::assert_matches,
bincode::{deserialize, serialize},
std::u16,
};

#[test]
fn test_short_u16_human_readable_serialization() {
let value = ShortU16(0u16);
let string = serde_json::to_string(&value).unwrap();
let expected_string = String::from("0");
assert_eq!(string, expected_string);
let deser_value: ShortU16 = serde_json::from_str(&string).unwrap();
assert_eq!(value.0, deser_value.0);

let value = ShortU16(u16::MAX);
let string = serde_json::to_string(&value).unwrap();
let expected_string = String::from("65535");
assert_eq!(string, expected_string);
let deser_value: ShortU16 = serde_json::from_str(&string).unwrap();
assert_eq!(value.0, deser_value.0);
}

#[test]
fn test_short_vec_human_readable_serialization() {
let value = ShortVec::<()>(vec![]);
let string = serde_json::to_string(&value).unwrap();
let expected_string = String::from("[]");
assert_eq!(string, expected_string);
let deser_value: ShortVec<()> = serde_json::from_str(&string).unwrap();
assert_eq!(value.0, deser_value.0);

let value = ShortVec(vec![1, 2, 3]);
let string = serde_json::to_string(&value).unwrap();
let expected_string = String::from("[1,2,3]");
assert_eq!(string, expected_string);
let deser_value: ShortVec<usize> = serde_json::from_str(&string).unwrap();
assert_eq!(value.0, deser_value.0);
}

/// Return the serialized length.
fn encode_len(len: u16) -> Vec<u8> {
bincode::serialize(&ShortU16(len)).unwrap()
Expand Down Expand Up @@ -372,13 +427,6 @@ mod tests {
assert_matches!(serialize(&vec), Err(_));
}

#[test]
fn test_short_vec_json() {
let vec = ShortVec(vec![0, 1, 2]);
let s = serde_json::to_string(&vec).unwrap();
assert_eq!(s, "[[3],0,1,2]");
}

#[test]
fn test_short_vec_aliased_length() {
let bytes = [
Expand Down
2 changes: 1 addition & 1 deletion transaction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const NONCED_TX_MARKER_IX_INDEX: u8 = 0;
#[cfg_attr(
feature = "frozen-abi",
derive(solana_frozen_abi_macro::AbiExample),
solana_frozen_abi_macro::frozen_abi(digest = "BLig4G2ysd7dcensK9bhKtnKvCQc1n65XdanyzsdWGXN")
solana_frozen_abi_macro::frozen_abi(digest = "5V7i4Tngkou3ieDNdtPpwYaFZpe2S2vZL71wrdJq5zTQ")
)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Default, Eq, Clone)]
Expand Down
Loading