Skip to content

Commit

Permalink
Merge #4980
Browse files Browse the repository at this point in the history
4980: Some types and enum variants were not properly json-serializing r=zajko a=zajko

The types/enum variants that changed:
* DelegatorKind::Purse(uref_addr) (uref_addr used to json-serialize as array of u8, now it json-serializes as a base16 encoded string of that vec)
* UnbondKind::DelegatedPurse (uref_addr) (uref_addr used to json-serialize as array of u8, now it json-serializes as a base16 encoded string of that vec)
* StoredValue::RawBytes(raw_bytes_vec) -> raw_bytes_vec serialized as an array of u8, but based on how we serialize Bytes in StoredValue::ContractWasm::bytes I changed it that it serializes as a string (to be consistent with serialization of Bytes type)

This will affect casper-client-rs and sidecar.

Co-authored-by: Jakub Zajkowski <[email protected]>
  • Loading branch information
casperlabs-bors-ng[bot] and Jakub Zajkowski authored Nov 27, 2024
2 parents 6191928 + cad32f7 commit bf56812
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 42 deletions.
25 changes: 3 additions & 22 deletions resources/test/sse_data_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2449,14 +2449,7 @@
],
"properties": {
"Purse": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
},
"maxItems": 32,
"minItems": 32
"type": "string"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -3245,14 +3238,7 @@
],
"properties": {
"DelegatedPurse": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
},
"maxItems": 32,
"minItems": 32
"type": "string"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -3937,12 +3923,7 @@
],
"properties": {
"RawBytes": {
"type": "array",
"items": {
"type": "integer",
"format": "uint8",
"minimum": 0.0
}
"type": "string"
}
},
"additionalProperties": false
Expand Down
21 changes: 16 additions & 5 deletions types/src/stored_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub enum StoredValue {
EntryPoint(EntryPointValue),
/// Raw bytes. Similar to a [`crate::StoredValue::CLValue`] but does not incur overhead of a
/// [`crate::CLValue`] and [`crate::CLType`].
RawBytes(Vec<u8>),
RawBytes(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] Vec<u8>),
}

impl StoredValue {
Expand Down Expand Up @@ -915,7 +915,7 @@ mod serde_helpers {
Reservation(&'a PrepaidKind),
EntryPoint(&'a EntryPointValue),
/// Raw bytes.
RawBytes(&'a Vec<u8>),
RawBytes(Bytes),
}

#[derive(Deserialize)]
Expand All @@ -940,7 +940,7 @@ mod serde_helpers {
NamedKey(NamedKeyValue),
EntryPoint(EntryPointValue),
/// Raw bytes.
RawBytes(Vec<u8>),
RawBytes(Bytes),
}

impl<'a> From<&'a StoredValue> for HumanReadableSerHelper<'a> {
Expand Down Expand Up @@ -976,7 +976,9 @@ mod serde_helpers {
StoredValue::NamedKey(payload) => HumanReadableSerHelper::NamedKey(payload),
StoredValue::Prepaid(payload) => HumanReadableSerHelper::Reservation(payload),
StoredValue::EntryPoint(payload) => HumanReadableSerHelper::EntryPoint(payload),
StoredValue::RawBytes(bytes) => HumanReadableSerHelper::RawBytes(bytes),
StoredValue::RawBytes(bytes) => {
HumanReadableSerHelper::RawBytes(bytes.as_slice().into())
}
}
}
}
Expand Down Expand Up @@ -1015,7 +1017,7 @@ mod serde_helpers {
}
HumanReadableDeserHelper::NamedKey(payload) => StoredValue::NamedKey(payload),
HumanReadableDeserHelper::EntryPoint(payload) => StoredValue::EntryPoint(payload),
HumanReadableDeserHelper::RawBytes(bytes) => StoredValue::RawBytes(bytes),
HumanReadableDeserHelper::RawBytes(bytes) => StoredValue::RawBytes(bytes.into()),
}
}
}
Expand Down Expand Up @@ -1113,6 +1115,15 @@ mod tests {
.contains("duplicate contract version: ContractVersionKey(1, 1)"));
}

#[test]
fn json_serialization_of_raw_bytes() {
let stored_value = StoredValue::RawBytes(vec![1, 2, 3, 4]);
assert_eq!(
serde_json::to_string(&stored_value).unwrap(),
r#"{"RawBytes":"01020304"}"#
);
}

proptest! {

#[test]
Expand Down
173 changes: 167 additions & 6 deletions types/src/system/auction/delegator_kind.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
bytesrepr,
bytesrepr::{FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
CLType, CLTyped, PublicKey, URef, URefAddr,
checksummed_hex, CLType, CLTyped, PublicKey, URef, URefAddr,
};
use alloc::vec::Vec;
use alloc::{string::String, vec::Vec};
use core::{
fmt,
fmt::{Display, Formatter},
Expand All @@ -17,7 +17,8 @@ use rand::{
};
#[cfg(feature = "json-schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
use serde_helpers::{HumanReadableDelegatorKind, NonHumanReadableDelegatorKind};

/// DelegatorKindTag variants.
#[repr(u8)]
Expand All @@ -30,15 +31,15 @@ pub enum DelegatorKindTag {
}

/// Auction bid variants.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, PartialOrd, Ord)]
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
#[cfg_attr(feature = "datasize", derive(DataSize))]
#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
/// Kinds of delegation bids.
pub enum DelegatorKind {
/// Delegation from public key.
PublicKey(PublicKey),
/// Delegation from purse.
Purse(URefAddr),
Purse(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] URefAddr),
}

impl DelegatorKind {
Expand Down Expand Up @@ -155,9 +156,169 @@ impl Distribution<DelegatorKind> for Standard {
}
}

impl Serialize for DelegatorKind {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
HumanReadableDelegatorKind::from(self).serialize(serializer)
} else {
NonHumanReadableDelegatorKind::from(self).serialize(serializer)
}
}
}

#[derive(Debug)]
enum DelegatorKindError {
DeserializationError(String),
}

impl Display for DelegatorKindError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
DelegatorKindError::DeserializationError(error) => {
write!(f, "Error when deserializing DelegatorKind: {}", error)
}
}
}
}

impl TryFrom<HumanReadableDelegatorKind> for DelegatorKind {
type Error = DelegatorKindError;

fn try_from(value: HumanReadableDelegatorKind) -> Result<Self, Self::Error> {
match value {
HumanReadableDelegatorKind::PublicKey(public_key) => {
Ok(DelegatorKind::PublicKey(public_key))
}
HumanReadableDelegatorKind::Purse(encoded) => {
let decoded = checksummed_hex::decode(encoded).map_err(|e| {
DelegatorKindError::DeserializationError(format!(
"Failed to decode encoded URefAddr: {}",
e
))
})?;
let uref_addr = URefAddr::try_from(decoded.as_ref()).map_err(|e| {
DelegatorKindError::DeserializationError(format!(
"Failed to build uref address: {}",
e
))
})?;
Ok(DelegatorKind::Purse(uref_addr))
}
}
}
}

impl From<NonHumanReadableDelegatorKind> for DelegatorKind {
fn from(value: NonHumanReadableDelegatorKind) -> Self {
match value {
NonHumanReadableDelegatorKind::PublicKey(public_key) => {
DelegatorKind::PublicKey(public_key)
}
NonHumanReadableDelegatorKind::Purse(addr) => DelegatorKind::Purse(addr),
}
}
}

impl<'de> Deserialize<'de> for DelegatorKind {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
if deserializer.is_human_readable() {
let human_readable = HumanReadableDelegatorKind::deserialize(deserializer)?;
DelegatorKind::try_from(human_readable)
.map_err(|error| SerdeError::custom(format!("{:?}", error)))
} else {
let non_human_readable = NonHumanReadableDelegatorKind::deserialize(deserializer)?;
Ok(DelegatorKind::from(non_human_readable))
}
}
}

mod serde_helpers {
use super::DelegatorKind;
use crate::{PublicKey, URefAddr};
use alloc::string::String;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub(super) enum HumanReadableDelegatorKind {
PublicKey(PublicKey),
Purse(String),
}

#[derive(Serialize, Deserialize)]
pub(super) enum NonHumanReadableDelegatorKind {
PublicKey(PublicKey),
Purse(URefAddr),
}

impl From<&DelegatorKind> for HumanReadableDelegatorKind {
fn from(delegator_kind: &DelegatorKind) -> Self {
match delegator_kind {
DelegatorKind::PublicKey(public_key) => {
HumanReadableDelegatorKind::PublicKey(public_key.clone())
}
DelegatorKind::Purse(uref_addr) => {
HumanReadableDelegatorKind::Purse(base16::encode_lower(uref_addr))
}
}
}
}

impl From<&DelegatorKind> for NonHumanReadableDelegatorKind {
fn from(delegator_kind: &DelegatorKind) -> Self {
match delegator_kind {
DelegatorKind::PublicKey(public_key) => {
NonHumanReadableDelegatorKind::PublicKey(public_key.clone())
}
DelegatorKind::Purse(uref_addr) => NonHumanReadableDelegatorKind::Purse(*uref_addr),
}
}
}
}

#[cfg(test)]
mod tests {
use crate::{bytesrepr, system::auction::delegator_kind::DelegatorKind, PublicKey, SecretKey};
use rand::Rng;

use crate::{
bytesrepr, system::auction::delegator_kind::DelegatorKind, testing::TestRng, PublicKey,
SecretKey,
};

#[test]
fn purse_serialized_as_string() {
let delegator_kind_payload = DelegatorKind::Purse([1; 32]);
let serialized = serde_json::to_string(&delegator_kind_payload).unwrap();
assert_eq!(
serialized,
"{\"Purse\":\"0101010101010101010101010101010101010101010101010101010101010101\"}"
);
}

#[test]
fn given_broken_address_purse_deserialziation_fails() {
let failing =
"{\"Purse\":\"Z101010101010101010101010101010101010101010101010101010101010101\"}";
let ret = serde_json::from_str::<DelegatorKind>(failing);
assert!(ret.is_err());
let failing = "{\"Purse\":\"01010101010101010101010101010101010101010101010101010101\"}";
let ret = serde_json::from_str::<DelegatorKind>(failing);
assert!(ret.is_err());
}

#[test]
fn json_roundtrip() {
let rng = &mut TestRng::new();

let delegator_kind_payload = DelegatorKind::PublicKey(PublicKey::random(rng));
let json_string = serde_json::to_string_pretty(&delegator_kind_payload).unwrap();
let decoded: DelegatorKind = serde_json::from_str(&json_string).unwrap();
assert_eq!(decoded, delegator_kind_payload);

let delegator_kind_payload = DelegatorKind::Purse(rng.gen());
let json_string = serde_json::to_string_pretty(&delegator_kind_payload).unwrap();
let decoded: DelegatorKind = serde_json::from_str(&json_string).unwrap();
assert_eq!(decoded, delegator_kind_payload);
}

#[test]
fn serialization_roundtrip() {
Expand Down
Loading

0 comments on commit bf56812

Please sign in to comment.