diff --git a/bitcoin/src/blockdata/script/borrowed.rs b/bitcoin/src/blockdata/script/borrowed.rs index fdecffc85..0c91715c1 100644 --- a/bitcoin/src/blockdata/script/borrowed.rs +++ b/bitcoin/src/blockdata/script/borrowed.rs @@ -9,14 +9,14 @@ use internals::ToU64 as _; use super::witness_version::WitnessVersion; use super::{ - bytes_to_asm_fmt, Builder, Instruction, InstructionIndices, Instructions, PushBytes, - RedeemScriptSizeError, ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError, + Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError, + ScriptBuf, ScriptHash, WScriptHash, WitnessScriptSizeError, }; use crate::consensus::Encodable; use crate::opcodes::all::*; use crate::opcodes::{self, Opcode}; use crate::policy::DUST_RELAY_TX_FEE; -use crate::prelude::{sink, Box, DisplayHex, String, ToOwned, Vec}; +use crate::prelude::{sink, Box, DisplayHex, String, ToOwned, ToString, Vec}; use crate::taproot::{LeafVersion, TapLeafHash}; use crate::FeeRate; @@ -483,16 +483,12 @@ crate::internal_macros::define_extension_trait! { /// Writes the human-readable assembly representation of the script to the formatter. #[deprecated(since = "TBD", note = "use the script's Display impl instead")] fn fmt_asm(&self, f: &mut dyn fmt::Write) -> fmt::Result { - bytes_to_asm_fmt(self.as_ref(), f) + write!(f, "{}", self) } /// Returns the human-readable assembly representation of the script. #[deprecated(since = "TBD", note = "use `to_string()` instead")] - fn to_asm_string(&self) -> String { - let mut buf = String::new(); - bytes_to_asm_fmt(self.as_ref(), &mut buf).expect("in-memory writers don't fail"); - buf - } + fn to_asm_string(&self) -> String { self.to_string() } /// Formats the script as lower-case hex. /// diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs index b6c07dbc5..7be207b83 100644 --- a/bitcoin/src/blockdata/script/mod.rs +++ b/bitcoin/src/blockdata/script/mod.rs @@ -415,7 +415,7 @@ impl AsMut<[u8]> for ScriptBuf { impl fmt::Debug for Script { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("Script(")?; - bytes_to_asm_fmt(self.as_ref(), f)?; + fmt::Display::fmt(self, f)?; f.write_str(")") } } @@ -425,8 +425,76 @@ impl fmt::Debug for ScriptBuf { } impl fmt::Display for Script { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { bytes_to_asm_fmt(self.as_ref(), f) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This has to be a macro because it needs to break the loop + macro_rules! read_push_data_len { + ($iter:expr, $size:path, $formatter:expr) => { + match script::read_push_data_len($iter, $size) { + Ok(n) => n, + Err(_) => { + $formatter.write_str("")?; + break; + } + } + }; + } + + let mut iter = self.as_bytes().iter(); + // Was at least one opcode emitted? + let mut at_least_one = false; + // `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead + // of `for`. + while let Some(byte) = iter.next() { + let opcode = Opcode::from(*byte); + + let data_len = if let opcodes::Class::PushBytes(n) = + opcode.classify(opcodes::ClassifyContext::Legacy) + { + n as usize + } else { + match opcode { + OP_PUSHDATA1 => { + // side effects: may write and break from the loop + read_push_data_len!(&mut iter, PushDataLenLen::One, f) + } + OP_PUSHDATA2 => { + // side effects: may write and break from the loop + read_push_data_len!(&mut iter, PushDataLenLen::Two, f) + } + OP_PUSHDATA4 => { + // side effects: may write and break from the loop + read_push_data_len!(&mut iter, PushDataLenLen::Four, f) + } + _ => 0, + } + }; + + if at_least_one { + f.write_str(" ")?; + } else { + at_least_one = true; + } + // Write the opcode + if opcode == OP_PUSHBYTES_0 { + f.write_str("OP_0")?; + } else { + write!(f, "{:?}", opcode)?; + } + // Write any pushdata + if data_len > 0 { + f.write_str(" ")?; + if data_len <= iter.len() { + for ch in iter.by_ref().take(data_len) { + write!(f, "{:02x}", ch)?; + } + } else { + f.write_str("")?; + break; + } + } + } + Ok(()) + } } impl fmt::Display for ScriptBuf { @@ -637,78 +705,6 @@ impl Decodable for ScriptBuf { } } -/// Writes the assembly decoding of the script bytes to the formatter. -pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Result { - // This has to be a macro because it needs to break the loop - macro_rules! read_push_data_len { - ($iter:expr, $size:path, $formatter:expr) => { - match script::read_push_data_len($iter, $size) { - Ok(n) => n, - Err(_) => { - $formatter.write_str("")?; - break; - } - } - }; - } - - let mut iter = script.iter(); - // Was at least one opcode emitted? - let mut at_least_one = false; - // `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead - // of `for`. - while let Some(byte) = iter.next() { - let opcode = Opcode::from(*byte); - - let data_len = if let opcodes::Class::PushBytes(n) = - opcode.classify(opcodes::ClassifyContext::Legacy) - { - n as usize - } else { - match opcode { - OP_PUSHDATA1 => { - // side effects: may write and break from the loop - read_push_data_len!(&mut iter, PushDataLenLen::One, f) - } - OP_PUSHDATA2 => { - // side effects: may write and break from the loop - read_push_data_len!(&mut iter, PushDataLenLen::Two, f) - } - OP_PUSHDATA4 => { - // side effects: may write and break from the loop - read_push_data_len!(&mut iter, PushDataLenLen::Four, f) - } - _ => 0, - } - }; - - if at_least_one { - f.write_str(" ")?; - } else { - at_least_one = true; - } - // Write the opcode - if opcode == OP_PUSHBYTES_0 { - f.write_str("OP_0")?; - } else { - write!(f, "{:?}", opcode)?; - } - // Write any pushdata - if data_len > 0 { - f.write_str(" ")?; - if data_len <= iter.len() { - for ch in iter.by_ref().take(data_len) { - write!(f, "{:02x}", ch)?; - } - } else { - f.write_str("")?; - break; - } - } - } - Ok(()) -} - /// Ways that a script might fail. Not everything is split up as /// much as it could be; patches welcome if more detailed errors /// would help you.