Add Debug derive and remove Debug, Display and serde::Serialize impls
What changed, and why it matters
This commit is a routine code cleanup, not a security fix. It removes some text-formatting features from the Bitcoin opcode type and replaces them with a simpler automatically-generated debug format. The change is driven by Rust language rules (orphan rules) that prevent adding certain traits once a type moves to another crate. Existing string output remains available through Opcode::as_str().
No security action required. Review downstream consumers that relied on Opcode implementing Display or serde::Serialize; they must now use Opcode::as_str() explicitly.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit removes manual fmt::Display, fmt::Debug, and serde::Serialize implementations for Opcode and adds a derived Debug implementation instead. This is necessitated by Rust orphan rules: once Opcode moves to the rust-bitcoin primitives crate, those foreign trait impls cannot be provided from the bitcoin crate. A derived Debug stays with the type, preserving assert_eq! usability. Serialization tests are updated to call op.as_str() explicitly. No vulnerability is patched.
Changed components
bitcoin/src/blockdata/opcodes.rsbitcoin/tests/serde_opcodes.rsInspect captured patch +7 / −27
diff --git a/bitcoin/src/blockdata/opcodes.rs b/bitcoin/src/blockdata/opcodes.rs
index 65ba964f..715636ce 100644
--- a/bitcoin/src/blockdata/opcodes.rs
+++ b/bitcoin/src/blockdata/opcodes.rs
@@ -22,7 +22,7 @@ use core::fmt;
/// Bitcoin Core's `IsPushOnly` considers `OP_RESERVED` to be a "push code", allowing this opcode
/// in contexts where only pushes are supposed to be allowed.
/// </details>
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Opcode {
code: u8,
}
@@ -117,12 +117,6 @@ macro_rules! all_opcodes {
#[deprecated(since = "TBD", note = "use OP_16 instead")]
pub const OP_PUSHNUM_16: Opcode = OP_16;
}
-
- impl fmt::Display for Opcode {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- core::fmt::Display::fmt(self.as_str(), f)
- }
- }
}
}
@@ -415,20 +409,6 @@ impl From<u8> for Opcode {
fn from(b: u8) -> Self { Self::from_u8(b) }
}
-impl fmt::Debug for Opcode {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) }
-}
-
-#[cfg(feature = "serde")]
-impl serde::Serialize for Opcode {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- serializer.serialize_str(self.as_str())
- }
-}
-
mod sealed {
pub trait Sealed {}
impl Sealed for super::Opcode {}
@@ -578,7 +558,7 @@ macro_rules! ordinary_opcode {
fn with(b: Opcode) -> Self {
match b {
$( $op => { Ordinary::$op } ),*
- _ => unreachable!("construction of `Ordinary` type from non-ordinary opcode {}", b),
+ _ => unreachable!("construction of `Ordinary` type from non-ordinary opcode {}", b.as_str()),
}
}
@@ -637,9 +617,7 @@ mod tests {
($unique:expr, $op:ident) => {
assert_eq!($op, Opcode::from($op.to_u8()));
- let s1 = format!("{}", $op);
- let s2 = format!("{:?}", $op);
- assert_eq!(s1, s2);
+ let s1 = format!("{}", $op.as_str());
assert_eq!(s1, stringify!($op));
assert!($unique.insert(s1));
};
@@ -648,7 +626,7 @@ mod tests {
#[test]
fn formatting_works() {
let op = all::OP_NOP;
- let s = format!("{:>10}", op);
+ let s = format!("{:>10}", op.as_str());
assert_eq!(s, " OP_NOP");
}
diff --git a/bitcoin/tests/serde_opcodes.rs b/bitcoin/tests/serde_opcodes.rs
index a94d3f96..0ca1b21d 100644
--- a/bitcoin/tests/serde_opcodes.rs
+++ b/bitcoin/tests/serde_opcodes.rs
@@ -6,12 +6,14 @@
extern crate bitcoin;
extern crate serde_json;
+use bitcoin::opcodes::OpcodeExt as _;
+
macro_rules! test_opcodes {
($($op:ident),* $(,)+) => {
$(
let op = bitcoin::opcodes::all::$op;
let want = concat!("\"", stringify!($op), "\"");
- let got = ::serde_json::to_string(&op).unwrap();
+ let got = ::serde_json::to_string(&op.as_str()).unwrap();
assert_eq!(got, want);
)*
}
Why this scored 19/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.