From bd86b1903071473136b682908737bd0f91a250e0 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 8 Jan 2024 20:38:34 -0800 Subject: [PATCH] Backfill changes to next for json rendering (#340) --- Makefile | 11 +- src/next/generated.rs | 61 ++------ src/next/mod.rs | 2 + src/next/str.rs | 327 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 57 deletions(-) create mode 100644 src/next/str.rs diff --git a/Makefile b/Makefile index dba0e961..2e14d4f8 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +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=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 +XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12 all: build test @@ -37,12 +38,12 @@ ifeq ($(LOCAL_XDRGEN),) docker run -i --rm -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\ gem install specific_install -v 0.3.8 && \ gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_VERSION) && \ - xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL) $^ \ + xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) $^ \ ' else docker run -i --rm -v $$PWD/../xdrgen:/xdrgen -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\ pushd /xdrgen && bundle install --deployment && rake install && popd && \ - xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL) $^ \ + xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) $^ \ ' endif rustfmt $@ @@ -56,12 +57,12 @@ ifeq ($(LOCAL_XDRGEN),) docker run -i --rm -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\ gem install specific_install -v 0.3.8 && \ gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_VERSION) && \ - xdrgen --language rust --namespace generated --output src/next $^ \ + xdrgen --language rust --namespace generated --output src/next --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) $^ \ ' else docker run -i --rm -v $$PWD/../xdrgen:/xdrgen -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\ pushd /xdrgen && bundle install --deployment && rake install && popd && \ - xdrgen --language rust --namespace generated --output src/next $^ \ + xdrgen --language rust --namespace generated --output src/next --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) $^ \ ' endif rustfmt $@ diff --git a/src/next/generated.rs b/src/next/generated.rs index 5628b9e2..c80c8cdc 100644 --- a/src/next/generated.rs +++ b/src/next/generated.rs @@ -8528,8 +8528,7 @@ impl WriteXdr for ScAddressType { #[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 ScAddress { @@ -10515,23 +10514,6 @@ impl core::fmt::Debug for AssetCode4 { Ok(()) } } -impl core::fmt::Display for AssetCode4 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let v = &self.0; - for b in v { - write!(f, "{b:02x}")?; - } - Ok(()) - } -} - -#[cfg(feature = "alloc")] -impl core::str::FromStr for AssetCode4 { - type Err = Error; - fn from_str(s: &str) -> core::result::Result { - hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() - } -} impl From for [u8; 4] { #[must_use] fn from(x: AssetCode4) -> Self { @@ -10633,23 +10615,6 @@ impl core::fmt::Debug for AssetCode12 { Ok(()) } } -impl core::fmt::Display for AssetCode12 { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let v = &self.0; - for b in v { - write!(f, "{b:02x}")?; - } - Ok(()) - } -} - -#[cfg(feature = "alloc")] -impl core::str::FromStr for AssetCode12 { - type Err = Error; - fn from_str(s: &str) -> core::result::Result { - hex::decode(s).map_err(|_| Error::InvalidHex)?.try_into() - } -} impl From for [u8; 12] { #[must_use] fn from(x: AssetCode12) -> Self { @@ -10865,8 +10830,7 @@ impl WriteXdr for AssetType { #[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 AssetCode { @@ -24126,8 +24090,7 @@ impl WriteXdr for LiquidityPoolParameters { #[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) )] pub struct MuxedAccountMed25519 { pub id: u64, @@ -24178,8 +24141,7 @@ impl WriteXdr for MuxedAccountMed25519 { #[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 MuxedAccount { @@ -41371,8 +41333,7 @@ impl WriteXdr for SignerKeyType { #[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 PublicKey { @@ -41474,8 +41435,7 @@ impl WriteXdr for PublicKey { #[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) )] pub struct SignerKeyEd25519SignedPayload { pub ed25519: Uint256, @@ -41534,8 +41494,7 @@ impl WriteXdr for SignerKeyEd25519SignedPayload { #[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 SignerKey { @@ -41875,8 +41834,7 @@ impl AsRef<[u8]> for SignatureHint { #[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) )] #[derive(Debug)] pub struct NodeId(pub PublicKey); @@ -41930,8 +41888,7 @@ impl WriteXdr for NodeId { #[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) )] #[derive(Debug)] pub struct AccountId(pub PublicKey); diff --git a/src/next/mod.rs b/src/next/mod.rs index a36c0299..8ab0180c 100644 --- a/src/next/mod.rs +++ b/src/next/mod.rs @@ -1,6 +1,8 @@ mod generated; pub use generated::*; +mod str; + mod scval_conversions; pub use scval_conversions::*; diff --git a/src/next/str.rs b/src/next/str.rs new file mode 100644 index 00000000..c00d65bb --- /dev/null +++ b/src/next/str.rs @@ -0,0 +1,327 @@ +//# Custom string representations of the following types, also used for JSON +//# formatting. +//# +//# The types that has impls in this file are given to the xdrgen +//# --rust-types-custom-str-impl cli option, so that xdrgen does not generate +//# FromStr and Display impls for them. +//# +//# ## Strkey Types (SEP-23) +//# - PublicKey +//# - AccountId +//# - MuxedAccount +//# - MuxedAccountMed25519 +//# - SignerKey +//# - SignerKeyEd25519SignedPayload +//# - NodeId +//# +//# ## Asset Codes +//# - AssetCode +//# - AssetCode4 +//# - AssetCode12 +#![cfg(feature = "alloc")] + +use super::{ + AccountId, AssetCode, AssetCode12, AssetCode4, Error, Hash, MuxedAccount, MuxedAccountMed25519, + NodeId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, Uint256, +}; + +impl From for Error { + fn from(_: stellar_strkey::DecodeError) -> Self { + Error::Invalid + } +} + +impl core::fmt::Display for PublicKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + PublicKey::PublicKeyTypeEd25519(Uint256(k)) => { + let k = stellar_strkey::ed25519::PublicKey::from_payload(k) + .map_err(|_| core::fmt::Error)?; + let s = k.to_string(); + f.write_str(&s)?; + } + } + Ok(()) + } +} + +impl core::str::FromStr for PublicKey { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let stellar_strkey::ed25519::PublicKey(k) = + stellar_strkey::ed25519::PublicKey::from_str(s)?; + Ok(PublicKey::PublicKeyTypeEd25519(Uint256(k))) + } +} + +impl core::fmt::Display for AccountId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.fmt(f) + } +} + +impl core::str::FromStr for AccountId { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + Ok(AccountId(PublicKey::from_str(s)?)) + } +} + +impl core::fmt::Display for MuxedAccountMed25519 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let MuxedAccountMed25519 { + ed25519: Uint256(ed25519), + id, + } = self; + let k = stellar_strkey::ed25519::MuxedAccount { + ed25519: *ed25519, + id: *id, + }; + let s = k.to_string(); + f.write_str(&s)?; + Ok(()) + } +} + +impl core::str::FromStr for MuxedAccountMed25519 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let stellar_strkey::ed25519::MuxedAccount { ed25519, id } = + stellar_strkey::ed25519::MuxedAccount::from_str(s)?; + Ok(MuxedAccountMed25519 { + ed25519: Uint256(ed25519), + id, + }) + } +} + +impl core::str::FromStr for MuxedAccount { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let strkey = stellar_strkey::Strkey::from_str(s)?; + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => { + Ok(MuxedAccount::Ed25519(Uint256(k))) + } + stellar_strkey::Strkey::MuxedAccountEd25519( + stellar_strkey::ed25519::MuxedAccount { ed25519, id }, + ) => Ok(MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { + ed25519: Uint256(ed25519), + id, + })), + stellar_strkey::Strkey::PrivateKeyEd25519(_) + | stellar_strkey::Strkey::PreAuthTx(_) + | stellar_strkey::Strkey::HashX(_) + | stellar_strkey::Strkey::SignedPayloadEd25519(_) + | stellar_strkey::Strkey::Contract(_) => Err(Error::Invalid), + } + } +} + +impl core::fmt::Display for MuxedAccount { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + MuxedAccount::Ed25519(Uint256(k)) => { + let k = stellar_strkey::ed25519::PublicKey(*k); + let s = k.to_string(); + f.write_str(&s)?; + } + MuxedAccount::MuxedEd25519(m) => m.fmt(f)?, + } + Ok(()) + } +} + +impl core::fmt::Display for NodeId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.fmt(f) + } +} + +impl core::str::FromStr for NodeId { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + Ok(NodeId(PublicKey::from_str(s)?)) + } +} + +impl core::fmt::Display for SignerKeyEd25519SignedPayload { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let SignerKeyEd25519SignedPayload { + ed25519: Uint256(ed25519), + payload, + } = self; + let k = stellar_strkey::ed25519::SignedPayload { + ed25519: *ed25519, + payload: payload.into(), + }; + let s = k.to_string(); + f.write_str(&s)?; + Ok(()) + } +} + +impl core::str::FromStr for SignerKeyEd25519SignedPayload { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let stellar_strkey::ed25519::SignedPayload { ed25519, payload } = + stellar_strkey::ed25519::SignedPayload::from_str(s)?; + Ok(SignerKeyEd25519SignedPayload { + ed25519: Uint256(ed25519), + payload: payload.try_into()?, + }) + } +} + +impl core::str::FromStr for SignerKey { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let strkey = stellar_strkey::Strkey::from_str(s)?; + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => { + Ok(SignerKey::Ed25519(Uint256(k))) + } + stellar_strkey::Strkey::PreAuthTx(stellar_strkey::PreAuthTx(h)) => { + Ok(SignerKey::PreAuthTx(Uint256(h))) + } + stellar_strkey::Strkey::HashX(stellar_strkey::HashX(h)) => { + Ok(SignerKey::HashX(Uint256(h))) + } + stellar_strkey::Strkey::SignedPayloadEd25519( + stellar_strkey::ed25519::SignedPayload { ed25519, payload }, + ) => Ok(SignerKey::Ed25519SignedPayload( + SignerKeyEd25519SignedPayload { + ed25519: Uint256(ed25519), + payload: payload.try_into()?, + }, + )), + stellar_strkey::Strkey::PrivateKeyEd25519(_) + | stellar_strkey::Strkey::Contract(_) + | stellar_strkey::Strkey::MuxedAccountEd25519(_) => Err(Error::Invalid), + } + } +} + +impl core::fmt::Display for SignerKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + SignerKey::Ed25519(Uint256(k)) => { + let k = stellar_strkey::ed25519::PublicKey(*k); + let s = k.to_string(); + f.write_str(&s)?; + } + SignerKey::PreAuthTx(Uint256(h)) => { + let k = stellar_strkey::PreAuthTx(*h); + let s = k.to_string(); + f.write_str(&s)?; + } + SignerKey::HashX(Uint256(h)) => { + let k = stellar_strkey::HashX(*h); + let s = k.to_string(); + f.write_str(&s)?; + } + SignerKey::Ed25519SignedPayload(p) => p.fmt(f)?, + } + Ok(()) + } +} + +impl core::str::FromStr for ScAddress { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let strkey = stellar_strkey::Strkey::from_str(s)?; + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => Ok( + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))), + ), + stellar_strkey::Strkey::Contract(stellar_strkey::Contract(h)) => { + Ok(ScAddress::Contract(Hash(h))) + } + stellar_strkey::Strkey::MuxedAccountEd25519(_) + | stellar_strkey::Strkey::PrivateKeyEd25519(_) + | stellar_strkey::Strkey::PreAuthTx(_) + | stellar_strkey::Strkey::HashX(_) + | stellar_strkey::Strkey::SignedPayloadEd25519(_) => Err(Error::Invalid), + } + } +} + +impl core::fmt::Display for ScAddress { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ScAddress::Account(a) => a.fmt(f)?, + ScAddress::Contract(Hash(h)) => { + let k = stellar_strkey::Contract(*h); + let s = k.to_string(); + f.write_str(&s)?; + } + } + Ok(()) + } +} + +impl core::str::FromStr for AssetCode4 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let mut code = AssetCode4([0u8; 4]); + escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?; + Ok(code) + } +} + +impl core::fmt::Display for AssetCode4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) { + for b in escape_bytes::Escape::new(&self.0[..=last_idx]) { + write!(f, "{}", b as char)?; + } + } + Ok(()) + } +} + +impl core::str::FromStr for AssetCode12 { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let mut code = AssetCode12([0u8; 12]); + escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?; + Ok(code) + } +} + +impl core::fmt::Display for AssetCode12 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) { + for b in escape_bytes::Escape::new(&self.0[..=last_idx]) { + write!(f, "{}", b as char)?; + } + } + Ok(()) + } +} + +impl core::str::FromStr for AssetCode { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let mut code = [0u8; 12]; + let n = escape_bytes::unescape_into(&mut code, s.as_bytes()).map_err(|_| Error::Invalid)?; + if n <= 4 { + Ok(AssetCode::CreditAlphanum4(AssetCode4([ + code[0], code[1], code[2], code[3], + ]))) + } else if n <= 12 { + Ok(AssetCode::CreditAlphanum12(AssetCode12(code))) + } else { + Err(Error::Invalid) + } + } +} + +impl core::fmt::Display for AssetCode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + AssetCode::CreditAlphanum4(c) => c.fmt(f), + AssetCode::CreditAlphanum12(c) => c.fmt(f), + } + } +}