Skip to content

Commit

Permalink
Encode claimable balance ids to match Horizon in JSON (#368)
Browse files Browse the repository at this point in the history
* fix claimable balance id render

* Encode claimable balance ids to match Horizon in JSON

* make str continue to work with alloc

* make str continue to work with alloc
  • Loading branch information
leighmcculloch authored May 14, 2024
1 parent efe941d commit 204ccb8
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 12 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features b
CARGO_DOC_ARGS?=--open

XDRGEN_VERSION=e2cac557162d99b12ae73b846cf3d5bfe16636de
XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12
XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12
XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId
XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId

all: build test

Expand Down
3 changes: 1 addition & 2 deletions src/curr/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14504,8 +14504,7 @@ impl WriteXdr for ClaimableBalanceIdType {
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(
all(feature = "serde", feature = "alloc"),
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "snake_case")
derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
)]
#[allow(clippy::large_enum_variant)]
pub enum ClaimableBalanceId {
Expand Down
45 changes: 43 additions & 2 deletions src/curr/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
//# - AssetCode
//# - AssetCode4
//# - AssetCode12
//#
//# ## Other
//# - ClaimableBalanceId
#![cfg(feature = "alloc")]

use super::{
AccountId, AssetCode, AssetCode12, AssetCode4, Error, Hash, MuxedAccount, MuxedAccountMed25519,
NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256,
AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, Error, Hash, MuxedAccount,
MuxedAccountMed25519, NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload,
Uint256,
};

impl From<stellar_strkey::DecodeError> for Error {
Expand Down Expand Up @@ -336,3 +340,40 @@ impl core::fmt::Display for AssetCode {
}
}
}

impl core::str::FromStr for ClaimableBalanceId {
type Err = Error;
fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
// This conversion to a hex string could be done by XDR encoding the
// self value, but because XDR encoding requires the std feature, this
// approach is taken instead to preserve the fact that the serde feature
// is available with alloc only.
let bytes = hex::decode(s).map_err(|_| Error::InvalidHex)?;
match bytes.as_slice() {
[0, 0, 0, 0, ..] => Ok(ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(
(&bytes[4..]).try_into()?,
))),
_ => Err(Error::Invalid),
}
}
}

impl core::fmt::Display for ClaimableBalanceId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// This conversion from a hex string could be done by XDR decoding the
// self value, but because XDR decoding requires the std feature, this
// approach is taken instead to preserve the fact that the serde feature
// is available with alloc only.
match self {
ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(bytes)) => {
for b in [0u8, 0, 0, 0] {
write!(f, "{b:02x}")?;
}
for b in bytes {
write!(f, "{b:02x}")?;
}
}
}
Ok(())
}
}
3 changes: 1 addition & 2 deletions src/next/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14504,8 +14504,7 @@ impl WriteXdr for ClaimableBalanceIdType {
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(
all(feature = "serde", feature = "alloc"),
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "snake_case")
derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
)]
#[allow(clippy::large_enum_variant)]
pub enum ClaimableBalanceId {
Expand Down
45 changes: 43 additions & 2 deletions src/next/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
//# - AssetCode
//# - AssetCode4
//# - AssetCode12
//#
//# ## Other
//# - ClaimableBalanceId
#![cfg(feature = "alloc")]

use super::{
AccountId, AssetCode, AssetCode12, AssetCode4, Error, Hash, MuxedAccount, MuxedAccountMed25519,
NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256,
AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, Error, Hash, MuxedAccount,
MuxedAccountMed25519, NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload,
Uint256,
};

impl From<stellar_strkey::DecodeError> for Error {
Expand Down Expand Up @@ -325,3 +329,40 @@ impl core::fmt::Display for AssetCode {
}
}
}

impl core::str::FromStr for ClaimableBalanceId {
type Err = Error;
fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
// This conversion to a hex string could be done by XDR encoding the
// self value, but because XDR encoding requires the std feature, this
// approach is taken instead to preserve the fact that the serde feature
// is available with alloc only.
let bytes = hex::decode(s).map_err(|_| Error::InvalidHex)?;
match bytes.as_slice() {
[0, 0, 0, 0, ..] => Ok(ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(
(&bytes[4..]).try_into()?,
))),
_ => Err(Error::Invalid),
}
}
}

impl core::fmt::Display for ClaimableBalanceId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// This conversion from a hex string could be done by XDR decoding the
// self value, but because XDR decoding requires the std feature, this
// approach is taken instead to preserve the fact that the serde feature
// is available with alloc only.
match self {
ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(bytes)) => {
for b in [0u8, 0, 0, 0] {
write!(f, "{b:02x}")?;
}
for b in bytes {
write!(f, "{b:02x}")?;
}
}
}
Ok(())
}
}
26 changes: 24 additions & 2 deletions tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
use stellar_xdr::curr as stellar_xdr;

use stellar_xdr::{
AccountId, AssetCode, AssetCode12, AssetCode4, Error, Hash, MuxedAccount, MuxedAccountMed25519,
NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256,
AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, Error, Hash, MuxedAccount,
MuxedAccountMed25519, NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload,
Uint256,
};

use std::str::FromStr;
Expand Down Expand Up @@ -541,3 +542,24 @@ fn asset_code_from_str_to_string_roundtrip_unicode() {
assert_eq!(AssetCode::CreditAlphanum4(AssetCode4(*b"a\xc3\xc3d")).to_string(), r"a\xc3\xc3d");
assert_eq!(AssetCode::from_str(r"a\xc3\xc3d"), Ok(AssetCode::CreditAlphanum4(AssetCode4(*b"a\xc3\xc3d"))));
}

#[test]
#[rustfmt::skip]
fn claimable_balance_id() {
assert_eq!(
ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash([1u8; 32])).to_string(),
"000000000101010101010101010101010101010101010101010101010101010101010101",
);
// Valid
assert_eq!(ClaimableBalanceId::from_str("000000000101010101010101010101010101010101010101010101010101010101010101"), Ok(ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash([1u8; 32]))));
// Half byte short.
assert_eq!(ClaimableBalanceId::from_str("00000000010101010101010101010101010101010101010101010101010101010101010"), Err(Error::InvalidHex));
// Full byte short.
assert_eq!(ClaimableBalanceId::from_str("0000000001010101010101010101010101010101010101010101010101010101010101"), Err(Error::LengthMismatch));
// Half byte too long.
assert_eq!(ClaimableBalanceId::from_str("0000000001010101010101010101010101010101010101010101010101010101010101011"), Err(Error::InvalidHex));
// Full byte too long.
assert_eq!(ClaimableBalanceId::from_str("00000000010101010101010101010101010101010101010101010101010101010101010101"), Err(Error::LengthMismatch));
// Unrecognized discriminant value.
assert_eq!(ClaimableBalanceId::from_str("000000010101010101010101010101010101010101010101010101010101010101010101"), Err(Error::Invalid));
}

0 comments on commit 204ccb8

Please sign in to comment.