Merge rust-bitcoin/rust-bitcoin#6644: primitives: Add serde impls for `WitnessVersion`
What changed, and why it matters
This commit adds standard serialization/deserialization support for the WitnessVersion type when the optional serde feature is enabled. It is a routine feature addition with no security relevance visible in the code or commit message.
No security action required; review as normal feature code.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements serde::Serialize and serde::Deserialize for bitcoin_primitives::witness_version::WitnessVersion behind #[cfg(feature = “serde”)]. Serialization emits the numeric witness version as a u8; deserialization parses a u8 and validates it via WitnessVersion::try_from, rejecting values outside 0..=16. The change also adds round-trip and invalid-input unit tests. No bug fixes, memory-safety changes, or cryptographic changes are present.
Changed components
primitives/src/witness_version.rsprimitives/api/all-features.txtInspect captured patch +50 / −0
### primitives/api/all-features.txt
@@ -6540,6 +6540,10 @@ impl core::marker::StructuralPartialEq for bitcoin_primitives::witness_version::
impl core::str::traits::FromStr for bitcoin_primitives::witness_version::WitnessVersion
pub type bitcoin_primitives::witness_version::WitnessVersion::Err = bitcoin_primitives::witness_version::error::ParseWitnessVersionError [impl: impl core::str::traits::FromStr for bitcoin_primitives::witness_version::WitnessVersion]
pub fn bitcoin_primitives::witness_version::WitnessVersion::from_str(s: &str) -> core::result::Result<Self, Self::Err> [impl: impl core::str::traits::FromStr for bitcoin_primitives::witness_version::WitnessVersion]
+impl serde::ser::Serialize for bitcoin_primitives::witness_version::WitnessVersion
+ pub fn bitcoin_primitives::witness_version::WitnessVersion::serialize<S>(&self, serializer: S) -> core::result::Result<<S as serde::ser::Serializer>::Ok, <S as serde::ser::Serializer>::Error> where S: serde::ser::Serializer [impl: impl serde::ser::Serialize for bitcoin_primitives::witness_version::WitnessVersion]
+impl<'de> serde::de::Deserialize<'de> for bitcoin_primitives::witness_version::WitnessVersion
+ pub fn bitcoin_primitives::witness_version::WitnessVersion::deserialize<D>(deserializer: D) -> core::result::Result<Self, <D as serde::de::Deserializer>::Error> where D: serde::de::Deserializer<'de> [impl: impl<'de> serde::de::Deserialize<'de> for bitcoin_primitives::witness_version::WitnessVersion]
impl core::marker::Freeze for bitcoin_primitives::witness_version::WitnessVersion
impl core::marker::Send for bitcoin_primitives::witness_version::WitnessVersion
impl core::marker::Sync for bitcoin_primitives::witness_version::WitnessVersion
@@ -6571,6 +6575,7 @@ impl<T> core::clone::CloneToUninit for bitcoin_primitives::witness_version::Witn
pub unsafe fn bitcoin_primitives::witness_version::WitnessVersion::clone_to_uninit(&self, dest: *mut u8) [impl: impl<T> core::clone::CloneToUninit for bitcoin_primitives::witness_version::WitnessVersion where T: core::clone::Clone]
impl<T> core::convert::From<T> for bitcoin_primitives::witness_version::WitnessVersion
pub fn bitcoin_primitives::witness_version::WitnessVersion::from(t: T) -> T [impl: impl<T> core::convert::From<T> for bitcoin_primitives::witness_version::WitnessVersion]
+impl<T> serde::de::DeserializeOwned for bitcoin_primitives::witness_version::WitnessVersion where T: for<'de> serde::de::Deserialize<'de>
pub struct bitcoin_primitives::witness_version::InvalidWitnessVersionError
impl bitcoin_primitives::witness_version::error::InvalidWitnessVersionError
pub fn bitcoin_primitives::witness_version::error::InvalidWitnessVersionError::invalid_version(&self) -> u8
### primitives/src/witness_version.rs
@@ -160,6 +160,27 @@ impl From<WitnessVersion> for Opcode {
}
}
+#[cfg(feature = "serde")]
+impl serde::Serialize for WitnessVersion {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_u8(self.to_num())
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de> serde::Deserialize<'de> for WitnessVersion {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let version = u8::deserialize(deserializer)?;
+ Self::try_from(version).map_err(serde::de::Error::custom)
+ }
+}
+
/// Error types for the segwit version number.
pub mod error {
use core::convert::Infallible;
@@ -292,6 +313,30 @@ mod tests {
assert_eq!(Opcode::from(WitnessVersion::V16), OP_16);
}
+ #[test]
+ #[cfg(feature = "serde")]
+ fn witness_version_serde_round_trip() {
+ for version in 0u8..=16 {
+ let wv = WitnessVersion::try_from(version).unwrap();
+
+ let json = serde_json::to_string(&wv).unwrap();
+ assert_eq!(json, format!("{}", version));
+ assert_eq!(serde_json::from_str::<WitnessVersion>(&json).unwrap(), wv);
+
+ let bin = bincode::serialize(&wv).unwrap();
+ assert_eq!(bin, bincode::serialize(&version).unwrap());
+ assert_eq!(bincode::deserialize::<WitnessVersion>(&bin).unwrap(), wv);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "serde")]
+ fn witness_version_serde_invalid() {
+ assert!(serde_json::from_str::<WitnessVersion>("17").is_err());
+ assert!(serde_json::from_str::<WitnessVersion>("255").is_err());
+ assert!(serde_json::from_str::<WitnessVersion>("-1").is_err());
+ }
+
#[test]
fn witness_version_opcode_round_trip() {
for version in 0u8..=16 {Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.