From fadd36891168933afa2abff5f1656bac13b8cc5f Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Mon, 26 Apr 2021 11:52:19 +0200 Subject: [PATCH 1/2] use different ser/de for Script in case of non human readable format --- src/blockdata/script.rs | 77 +++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 12844498..17a2e7c6 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -819,44 +819,59 @@ impl_index_newtype!(Builder, u8); #[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for Script { fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, + where D: serde::Deserializer<'de>, { use core::fmt::Formatter; use hashes::hex::FromHex; - struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = Script; + if deserializer.is_human_readable() { - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a script") - } + struct Visitor; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Script; - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - let v = Vec::from_hex(v).map_err(E::custom)?; - Ok(Script::from(v)) - } + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a script hex") + } - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: serde::de::Error, - { - self.visit_str(v) - } + fn visit_str(self, v: &str) -> Result + where E: serde::de::Error, + { + let v = Vec::from_hex(v).map_err(E::custom)?; + Ok(Script::from(v)) + } - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(&v) + fn visit_borrowed_str(self, v: &'de str) -> Result + where E: serde::de::Error, + { + self.visit_str(v) + } + + fn visit_string(self, v: String) -> Result + where E: serde::de::Error, + { + self.visit_str(&v) + } } + deserializer.deserialize_str(Visitor) + } else { + struct BytesVisitor; + + impl<'de> serde::de::Visitor<'de> for BytesVisitor { + type Value = Script; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a script Vec") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where E: serde::de::Error, + { + Ok(Script::from(v.to_vec())) + } + } + deserializer.deserialize_bytes(BytesVisitor) } - - deserializer.deserialize_str(Visitor) } } @@ -867,7 +882,11 @@ impl serde::Serialize for Script { where S: serde::Serializer, { - serializer.serialize_str(&format!("{:x}", self)) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("{:x}", self)) + } else { + serializer.serialize_bytes(&self.as_bytes()) + } } } From 4a4460b1a36d775dda51a9e2f7f4a33ca58d3dba Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Mon, 26 Apr 2021 11:51:19 +0200 Subject: [PATCH 2/2] Add test for script serialize/deserialize --- src/blockdata/script.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 17a2e7c6..605ddbfa 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -1293,5 +1293,22 @@ mod test { assert!(script_p2pkh.is_p2pkh()); assert_eq!(script_p2pkh.dust_value(), 546); } + + #[test] + #[cfg(feature = "serde")] + fn test_script_serde_human_and_not() { + let script = Script::from(vec![0u8, 1u8, 2u8]); + + // Serialize + let json = ::serde_json::to_string(&script).unwrap(); + assert_eq!(json, "\"000102\""); + let bincode = ::bincode::serialize(&script).unwrap(); + assert_eq!(bincode, [3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2]); // bincode adds u64 for length, serde_cbor use varint + + // Deserialize + assert_eq!(script, ::serde_json::from_str(&json).unwrap()); + assert_eq!(script, ::bincode::deserialize(&bincode).unwrap()); + } + }