Make Lower/Upper hex print scripts with len prefix
Add the length prefix when formatting hex strings by way of `LowerHex` and `UpperHex`. This looses formatting options because I can't remember right now how not to - again.
This commit is contained in:
parent
c27b95fb0d
commit
2b72f1f30b
|
@ -1,5 +1,12 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
//! Demonstrates the API for parsing and formatting Bitcoin scripts.
|
||||||
|
//!
|
||||||
|
//! Bitcoin script is conceptually a vector of bytes. As such it is consensus encoded with a compact
|
||||||
|
//! size encoded length prefix. See [CompactSize].
|
||||||
|
//!
|
||||||
|
//! [`CompactSize`]: <https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer>
|
||||||
|
|
||||||
use bitcoin::consensus::encode;
|
use bitcoin::consensus::encode;
|
||||||
use bitcoin::key::WPubkeyHash;
|
use bitcoin::key::WPubkeyHash;
|
||||||
use bitcoin::script::{self, ScriptExt, ScriptBufExt};
|
use bitcoin::script::{self, ScriptExt, ScriptBufExt};
|
||||||
|
@ -8,6 +15,7 @@ use bitcoin::ScriptBuf;
|
||||||
fn main() {
|
fn main() {
|
||||||
let pk = "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb".parse::<WPubkeyHash>().unwrap();
|
let pk = "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb".parse::<WPubkeyHash>().unwrap();
|
||||||
|
|
||||||
|
// TL;DR Use `to_hex_string` and `from_hex`.
|
||||||
let script_code = script::p2wpkh_script_code(pk);
|
let script_code = script::p2wpkh_script_code(pk);
|
||||||
let hex = script_code.to_hex_string();
|
let hex = script_code.to_hex_string();
|
||||||
let decoded = ScriptBuf::from_hex(&hex).unwrap();
|
let decoded = ScriptBuf::from_hex(&hex).unwrap();
|
||||||
|
@ -19,16 +27,19 @@ fn main() {
|
||||||
// We do not implement parsing scripts from human-readable format.
|
// We do not implement parsing scripts from human-readable format.
|
||||||
// let decoded = s.parse::<ScriptBuf>().unwrap();
|
// let decoded = s.parse::<ScriptBuf>().unwrap();
|
||||||
|
|
||||||
// This is not equivalent to consensus encoding i.e., does not include the length prefix.
|
// This is equivalent to consensus encoding i.e., includes the length prefix.
|
||||||
let hex_lower_hex_trait = format!("{:x}", script_code);
|
let hex_lower_hex_trait = format!("{:x}", script_code);
|
||||||
println!("hex created using `LowerHex`: {}", hex_lower_hex_trait);
|
println!("hex created using `LowerHex`: {}", hex_lower_hex_trait);
|
||||||
|
|
||||||
// The `deserialize_hex` function requires the length prefix.
|
// The `deserialize_hex` function requires the length prefix.
|
||||||
assert!(encode::deserialize_hex::<ScriptBuf>(&hex_lower_hex_trait).is_err());
|
assert_eq!(encode::deserialize_hex::<ScriptBuf>(&hex_lower_hex_trait).unwrap(), script_code);
|
||||||
// And so does `from_hex`.
|
// And so does `from_hex`.
|
||||||
assert!(ScriptBuf::from_hex(&hex_lower_hex_trait).is_err());
|
assert_eq!(ScriptBuf::from_hex(&hex_lower_hex_trait).unwrap(), script_code);
|
||||||
// But we provide an explicit constructor that does not.
|
|
||||||
assert_eq!(ScriptBuf::from_hex_no_length_prefix(&hex_lower_hex_trait).unwrap(), script_code);
|
// And we also provide an explicit constructor that does not use the length prefix.
|
||||||
|
let other = ScriptBuf::from_hex_no_length_prefix(&hex_lower_hex_trait).unwrap();
|
||||||
|
// Without a prefix the script parses but its not the one we meant.
|
||||||
|
assert_ne!(other, script_code);
|
||||||
|
|
||||||
// This is consensus encoding i.e., includes the length prefix.
|
// This is consensus encoding i.e., includes the length prefix.
|
||||||
let hex_inherent = script_code.to_hex_string(); // Defined in `ScriptExt`.
|
let hex_inherent = script_code.to_hex_string(); // Defined in `ScriptExt`.
|
||||||
|
@ -47,12 +58,7 @@ fn main() {
|
||||||
|
|
||||||
let decoded: ScriptBuf = encode::deserialize_hex(&encoded).unwrap();
|
let decoded: ScriptBuf = encode::deserialize_hex(&encoded).unwrap();
|
||||||
assert_eq!(decoded, script_code);
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
let decoded = ScriptBuf::from_hex(&encoded).unwrap();
|
|
||||||
assert_eq!(decoded, script_code);
|
|
||||||
|
|
||||||
// And we can mix these to calls because both include the length prefix.
|
// And we can mix these to calls because both include the length prefix.
|
||||||
let encoded = encode::serialize_hex(&script_code);
|
|
||||||
let decoded = ScriptBuf::from_hex(&encoded).unwrap();
|
let decoded = ScriptBuf::from_hex(&encoded).unwrap();
|
||||||
assert_eq!(decoded, script_code);
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
|
|
|
@ -431,9 +431,12 @@ impl fmt::Display for ScriptBuf {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
impl fmt::LowerHex for Script {
|
impl fmt::LowerHex for Script {
|
||||||
|
// Currently we drop all formatter options.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
|
let compact = internals::compact_size::encode(self.as_bytes().len());
|
||||||
|
write!(f, "{:x}", compact.as_slice().as_hex())?;
|
||||||
|
write!(f, "{:x}", self.as_bytes().as_hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -451,9 +454,12 @@ internals::impl_to_hex_from_lower_hex!(ScriptBuf, |script_buf: &Self| script_buf
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
impl fmt::UpperHex for Script {
|
impl fmt::UpperHex for Script {
|
||||||
|
// Currently we drop all formatter options.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
|
let compact = internals::compact_size::encode(self.as_bytes().len());
|
||||||
|
write!(f, "{:X}", compact.as_slice().as_hex())?;
|
||||||
|
write!(f, "{:X}", self.as_bytes().as_hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +511,8 @@ impl serde::Serialize for Script {
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
serializer.collect_str(&format_args!("{:x}", self))
|
// Do not call LowerHex because we don't want to add the len prefix.
|
||||||
|
serializer.collect_str(&format_args!("{}", self.as_bytes().as_hex()))
|
||||||
} else {
|
} else {
|
||||||
serializer.serialize_bytes(self.as_bytes())
|
serializer.serialize_bytes(self.as_bytes())
|
||||||
}
|
}
|
||||||
|
@ -796,8 +803,8 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
{
|
{
|
||||||
assert_eq!(format!("{:x}", script), "00a1b2");
|
assert_eq!(format!("{:x}", script), "0300a1b2");
|
||||||
assert_eq!(format!("{:X}", script), "00A1B2");
|
assert_eq!(format!("{:X}", script), "0300A1B2");
|
||||||
}
|
}
|
||||||
assert!(!format!("{:?}", script).is_empty());
|
assert!(!format!("{:?}", script).is_empty());
|
||||||
}
|
}
|
||||||
|
@ -809,8 +816,8 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
{
|
{
|
||||||
assert_eq!(format!("{:x}", script_buf), "00a1b2");
|
assert_eq!(format!("{:x}", script_buf), "0300a1b2");
|
||||||
assert_eq!(format!("{:X}", script_buf), "00A1B2");
|
assert_eq!(format!("{:X}", script_buf), "0300A1B2");
|
||||||
}
|
}
|
||||||
assert!(!format!("{:?}", script_buf).is_empty());
|
assert!(!format!("{:?}", script_buf).is_empty());
|
||||||
}
|
}
|
||||||
|
@ -928,7 +935,7 @@ mod tests {
|
||||||
fn script_to_hex() {
|
fn script_to_hex() {
|
||||||
let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]);
|
let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]);
|
||||||
let hex = script.to_hex();
|
let hex = script.to_hex();
|
||||||
assert_eq!(hex, "a1b2c3");
|
assert_eq!(hex, "03a1b2c3");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -937,6 +944,6 @@ mod tests {
|
||||||
fn scriptbuf_to_hex() {
|
fn scriptbuf_to_hex() {
|
||||||
let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]);
|
let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]);
|
||||||
let hex = script.to_hex();
|
let hex = script.to_hex();
|
||||||
assert_eq!(hex, "a1b2c3");
|
assert_eq!(hex, "03a1b2c3");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue