Skip to content

Commit

Permalink
Merge rust-bitcoin#4061: Make Debug representation of Witness to be s…
Browse files Browse the repository at this point in the history
…lice of hex-encoded bytes strings to improve readability

8d8edd2 make Debug representation of Witness to be slice of hex-encoded bytes strings (Erick Cestari)

Pull request description:

  This PR updates the Debug implementation for the Witness type to improve its readability by displaying the witness data as a slice of hex-encoded strings rather than a concatenated blob or list of raw u8 values. The changes include:

  - Improved Output:
  The debug output now shows pseudo-fields such as the number of elements and the total length of all elements, making it easier to understand the underlying data without exposing internal indices like indices_start.

  - Hex-Encoding:
  Each witness element is displayed as a hex-encoded string, similar to Bitcoin Core's output style, which enhances clarity during debugging sessions.

  These changes should provide a more developer-friendly view of the witness data and align with similar patterns used elsewhere in the ecosystem.

  Closes rust-bitcoin#4023.

  Example display:

  ```
  Witness {
      num_elements: 3,
      total_bytes: 5,
      elements: [
          0b,
          1516,
          1f20,
      ],
  }
  ```
  ```
  Witness { num_elements: 3, total_bytes: 5, elements: [0b, 1516, 1f20] }
  ```

ACKs for top commit:
  tcharding:
    ACK 8d8edd2
  Kixunil:
    ACK 8d8edd2
  apoelstra:
    ACK 8d8edd2; successfully ran local tests

Tree-SHA512: ffcdf67542049f405317eecd74876b51972d27ec552eec8e9c7b6324f18f31f4721fc4d2be1e596232c39af90a8d169c082f9b0636e5aa1a80fe1b063d645456
  • Loading branch information
apoelstra committed Feb 17, 2025
2 parents 7ea40b2 + 8d8edd2 commit fab1a97
Showing 1 changed file with 19 additions and 65 deletions.
84 changes: 19 additions & 65 deletions primitives/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::ops::Index;

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
use hex::DisplayHex;
use internals::compact_size;

use crate::prelude::Vec;
Expand Down Expand Up @@ -231,76 +232,29 @@ fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option<
}
}

impl fmt::Debug for Witness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
if f.alternate() {
fmt_debug_pretty(self, f)
} else {
fmt_debug(self, f)
}
}
}
/// Debug implementation that displays the witness as a structured output containing hex-encoded witness elements.
struct DebugElements<'a>(&'a Witness);

fn fmt_debug(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
#[rustfmt::skip]
let comma_or_close = |current_index, last_index| {
if current_index == last_index { "]" } else { ", " }
};

f.write_str("Witness: { ")?;
write!(f, "indices: {}, ", w.witness_elements)?;
write!(f, "indices_start: {}, ", w.indices_start)?;
f.write_str("witnesses: [")?;

let instructions = w.iter();
match instructions.len().checked_sub(1) {
Some(last_instruction) => {
for (i, instruction) in instructions.enumerate() {
let bytes = instruction.iter();
match bytes.len().checked_sub(1) {
Some(last_byte) => {
f.write_str("[")?;
for (j, byte) in bytes.enumerate() {
write!(f, "{:#04x}", byte)?;
f.write_str(comma_or_close(j, last_byte))?;
}
}
None => {
// This is possible because the varint is not part of the instruction (see Iter).
write!(f, "[]")?;
}
}
f.write_str(comma_or_close(i, last_instruction))?;
}
}
None => {
// Witnesses can be empty because the 0x00 var int is not stored in content.
write!(f, "]")?;
}
impl fmt::Debug for DebugElements<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter().map(|elem| elem.as_hex())).finish()
}

f.write_str(" }")
}

fn fmt_debug_pretty(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("Witness: {\n")?;
writeln!(f, " indices: {},", w.witness_elements)?;
writeln!(f, " indices_start: {},", w.indices_start)?;
f.write_str(" witnesses: [\n")?;

for instruction in w.iter() {
f.write_str(" [")?;
for (j, byte) in instruction.iter().enumerate() {
if j > 0 {
f.write_str(", ")?;
}
write!(f, "{:#04x}", byte)?;
}
f.write_str("],\n")?;
}
/// Debug implementation that displays the witness as a structured output containing:
/// - Number of witness elements
/// - Total bytes across all elements
/// - List of hex-encoded witness elements
impl fmt::Debug for Witness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let total_bytes: usize = self.iter().map(|elem| elem.len()).sum();

writeln!(f, " ],")?;
writeln!(f, "}}")
f.debug_struct("Witness")
.field("num_elements", &self.witness_elements)
.field("total_bytes", &total_bytes)
.field("elements", &DebugElements(self))
.finish()
}
}

/// An iterator returning individual witness elements.
Expand Down

0 comments on commit fab1a97

Please sign in to comment.