bark-bitcoin-ext 0.1.2

Extension library to the rust-bitcoin ecosystem crates used in bark
Documentation

pub mod encodable {
	//! Module to bytes- or hex-encode bitcoin objects using the bitcoin encoding
	//!
	//! It is not recommended to use this for types that already have a string-based
	//! serde encoding like `PublicKey` or the hashes like `Txid`.

	use std::fmt;
	use std::borrow::Cow;
	use std::marker::PhantomData;

	use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};

	use bitcoin::consensus::encode::{self, Decodable, Encodable};

	struct SerWrapper<'a, T>(&'a T);

	impl<'a, T: Encodable> Serialize for SerWrapper<'a, T> {
		fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
			if s.is_human_readable() {
				s.serialize_str(&encode::serialize_hex(&self.0))
			} else {
				s.serialize_bytes(&encode::serialize(&self.0))
			}
		}
	}

	struct DeWrapper<T>(T);

	impl<'de, T: Decodable> Deserialize<'de> for DeWrapper<T> {
		fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
			if d.is_human_readable() {
				let s = <Cow<'de, str>>::deserialize(d)?;
				Ok(DeWrapper(encode::deserialize_hex(s.as_ref())
					.map_err(serde::de::Error::custom)?))
			} else {
				let b = <Cow<'de, [u8]>>::deserialize(d)?;
				Ok(DeWrapper(encode::deserialize(b.as_ref())
					.map_err(serde::de::Error::custom)?))
			}
		}
	}

	pub fn serialize<T, S>(v: &T, s: S) -> Result<S::Ok, S::Error>
	where
		T: Encodable + Clone,
		S: Serializer,
	{
		SerWrapper(v).serialize(s)
	}

	pub fn deserialize<'d, T: Decodable, D: Deserializer<'d>>(d: D) -> Result<T, D::Error> {
		Ok(DeWrapper::<T>::deserialize(d)?.0)
	}

	pub mod vec {
		use super::*;

		pub fn serialize<T: Encodable, S: Serializer>(v: &[T], s: S) -> Result<S::Ok, S::Error> {
			let mut seq = s.serialize_seq(Some(v.len()))?;
			for item in v {
				ser::SerializeSeq::serialize_element(&mut seq, &SerWrapper(item))?;
			}
			ser::SerializeSeq::end(seq)
		}

		pub fn deserialize<'d, T: Decodable, D: Deserializer<'d>>(d: D) -> Result<Vec<T>, D::Error> {
			struct Visitor<T>(PhantomData<T>);

			impl<'de, T: Decodable> de::Visitor<'de> for Visitor<T> {
				type Value = Vec<T>;

				fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
					f.write_str("a vector of bitcoin-encoded objects")
				}

				fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
					let mut ret = Vec::with_capacity(seq.size_hint().unwrap_or_default());
					while let Some(v) = seq.next_element::<DeWrapper<T>>()? {
						ret.push(v.0);
					}
					Ok(ret)
				}
			}
			d.deserialize_seq(Visitor(PhantomData))
		}
	}

	pub mod cow {
		use super::*;

		pub fn serialize<'a, T, S>(v: &Cow<'a, T>, s: S) -> Result<S::Ok, S::Error>
		where
			T: Encodable + Clone,
			S: Serializer,
		{
			SerWrapper(v.as_ref()).serialize(s)
		}

		pub fn deserialize<'d, T, D>(d: D) -> Result<Cow<'static, T>, D::Error>
		where
			T: Decodable + Clone,
			D: Deserializer<'d>,
		{
			Ok(Cow::Owned(DeWrapper::<T>::deserialize(d)?.0))
		}
	}
}


#[cfg(test)]
mod test {
	use bitcoin::Transaction;

	#[test]
	fn test_serde_encodable() {
		let hex = "0200000000010151d0aa3be0ee0a27b2400f1eb9ddc692aace09c5d197475bceca711e0ba7ce320000000000ffffffff03ca2f03000000000022512043445259f5c414ce3fb6bd43d7caf8048f410351818fe4f0a26f95d010f653b7791b08000000000022512043445259f5c414ce3fb6bd43d7caf8048f410351818fe4f0a26f95d010f653b74a010000000000002200204ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc3326001408abb6b9c0a21c90d3b42e059f94536588b1a99288abfdb79bbcfd548f7e3bb105e52c5cd8cff388679df825a7d5f93004dd416b81cfa0af1c814df79d381994c00000000";
		let tx = bitcoin::consensus::encode::deserialize_hex::<Transaction>(&hex).unwrap();
		let raw = bitcoin::consensus::encode::serialize(&tx);
		assert_eq!(raw.len(), 248);

		#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
		struct S {
			#[serde(with = "crate::serde::encodable")]
			tx: Transaction,
		}

		let s = S { tx };
		let json = serde_json::to_string(&s).unwrap();
		assert_eq!(json.len(), 505);
		assert_eq!(json, "{\"tx\":\"0200000000010151d0aa3be0ee0a27b2400f1eb9ddc692aace09c5d197475bceca711e0ba7ce320000000000ffffffff03ca2f03000000000022512043445259f5c414ce3fb6bd43d7caf8048f410351818fe4f0a26f95d010f653b7791b08000000000022512043445259f5c414ce3fb6bd43d7caf8048f410351818fe4f0a26f95d010f653b74a010000000000002200204ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc3326001408abb6b9c0a21c90d3b42e059f94536588b1a99288abfdb79bbcfd548f7e3bb105e52c5cd8cff388679df825a7d5f93004dd416b81cfa0af1c814df79d381994c00000000\"}");

		let s_from_json = serde_json::from_str(&json).unwrap();
		assert_eq!(s, s_from_json);

		let rmp = rmp_serde::to_vec(&s).unwrap();
		assert_eq!(rmp.len(), 251);
		let s_from_rmp = rmp_serde::from_slice(&rmp).unwrap();
		assert_eq!(s, s_from_rmp);

		let nrmp = rmp_serde::to_vec_named(&s).unwrap();
		assert_eq!(nrmp.len(), 254);
		let s_from_nrmp = rmp_serde::from_slice(&nrmp).unwrap();
		assert_eq!(s, s_from_nrmp);
	}
}