Hex macro clean up

There were some duplicated hex macros in the `address` module as well as
several macros outputing specific types instead of working with any type
deserializable from hex.

This cleanup moves the macros and deduplicates them, introduces a new
`TestFromHex` trait to generalize parsing hex and rewrites the code to
use hex parsing generally. `hex_script` is still kept because its usage
is very frequent.
This commit is contained in:
Martin Habovstiak 2022-08-13 13:29:18 +02:00
parent 4dedf7d555
commit 43827a1e1c
4 changed files with 88 additions and 48 deletions

View File

@ -933,17 +933,11 @@ mod tests {
use secp256k1::XOnlyPublicKey; use secp256k1::XOnlyPublicKey;
use super::*; use super::*;
use crate::blockdata::script::Script;
use crate::hashes::hex::{FromHex, ToHex}; use crate::hashes::hex::{FromHex, ToHex};
use crate::internal_macros::{hex, hex_into, hex_script};
use crate::network::constants::Network::{Bitcoin, Testnet}; use crate::network::constants::Network::{Bitcoin, Testnet};
use crate::util::key::PublicKey; use crate::util::key::PublicKey;
macro_rules! hex (($hex:literal) => (Vec::from_hex($hex).unwrap()));
macro_rules! hex_key (($hex:literal) => (PublicKey::from_slice(&hex!($hex)).unwrap()));
macro_rules! hex_script (($hex:literal) => (Script::from(hex!($hex))));
macro_rules! hex_pubkeyhash (($hex:literal) => (PubkeyHash::from_hex(&$hex).unwrap()));
macro_rules! hex_scripthash (($hex:literal) => (ScriptHash::from_hex($hex).unwrap()));
fn roundtrips(addr: &Address) { fn roundtrips(addr: &Address) {
assert_eq!( assert_eq!(
Address::from_str(&addr.to_string()).unwrap(), Address::from_str(&addr.to_string()).unwrap(),
@ -964,9 +958,7 @@ mod tests {
fn test_p2pkh_address_58() { fn test_p2pkh_address_58() {
let addr = Address { let addr = Address {
network: Bitcoin, network: Bitcoin,
payload: Payload::PubkeyHash(hex_pubkeyhash!( payload: Payload::PubkeyHash(hex_into!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
"162c5ea71c0b23f5b9022ef047c4a86470a5b070"
)),
}; };
assert_eq!( assert_eq!(
@ -980,11 +972,11 @@ mod tests {
#[test] #[test]
fn test_p2pkh_from_key() { fn test_p2pkh_from_key() {
let key = hex_key!("048d5141948c1702e8c95f438815794b87f706a8d4cd2bffad1dc1570971032c9b6042a0431ded2478b5c9cf2d81c124a5e57347a3c63ef0e7716cf54d613ba183"); let key = hex_into!("048d5141948c1702e8c95f438815794b87f706a8d4cd2bffad1dc1570971032c9b6042a0431ded2478b5c9cf2d81c124a5e57347a3c63ef0e7716cf54d613ba183");
let addr = Address::p2pkh(&key, Bitcoin); let addr = Address::p2pkh(&key, Bitcoin);
assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY"); assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY");
let key = hex_key!("03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f"); let key = hex_into!("03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f");
let addr = Address::p2pkh(&key, Testnet); let addr = Address::p2pkh(&key, Testnet);
assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC"); assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC");
assert_eq!(addr.address_type(), Some(AddressType::P2pkh)); assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
@ -995,9 +987,7 @@ mod tests {
fn test_p2sh_address_58() { fn test_p2sh_address_58() {
let addr = Address { let addr = Address {
network: Bitcoin, network: Bitcoin,
payload: Payload::ScriptHash(hex_scripthash!( payload: Payload::ScriptHash(hex_into!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
"162c5ea71c0b23f5b9022ef047c4a86470a5b070"
)),
}; };
assert_eq!( assert_eq!(
@ -1028,7 +1018,7 @@ mod tests {
fn test_p2wpkh() { fn test_p2wpkh() {
// stolen from Bitcoin transaction: b3c8c2b6cfc335abbcb2c7823a8453f55d64b2b5125a9a61e8737230cdb8ce20 // stolen from Bitcoin transaction: b3c8c2b6cfc335abbcb2c7823a8453f55d64b2b5125a9a61e8737230cdb8ce20
let mut key = let mut key =
hex_key!("033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc"); hex_into!("033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc");
let addr = Address::p2wpkh(&key, Bitcoin).unwrap(); let addr = Address::p2wpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw"); assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw");
assert_eq!(addr.address_type(), Some(AddressType::P2wpkh)); assert_eq!(addr.address_type(), Some(AddressType::P2wpkh));
@ -1056,7 +1046,7 @@ mod tests {
fn test_p2shwpkh() { fn test_p2shwpkh() {
// stolen from Bitcoin transaction: ad3fd9c6b52e752ba21425435ff3dd361d6ac271531fc1d2144843a9f550ad01 // stolen from Bitcoin transaction: ad3fd9c6b52e752ba21425435ff3dd361d6ac271531fc1d2144843a9f550ad01
let mut key = let mut key =
hex_key!("026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766"); hex_into!("026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766");
let addr = Address::p2shwpkh(&key, Bitcoin).unwrap(); let addr = Address::p2shwpkh(&key, Bitcoin).unwrap();
assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE"); assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE");
assert_eq!(addr.address_type(), Some(AddressType::P2sh)); assert_eq!(addr.address_type(), Some(AddressType::P2sh));

View File

@ -123,11 +123,60 @@ pub(crate) use test_macros::*;
#[cfg(test)] #[cfg(test)]
mod test_macros { mod test_macros {
macro_rules! hex_script (($s:expr) => (<$crate::Script as core::str::FromStr>::from_str($s).unwrap())); use crate::hashes::hex::FromHex;
use crate::PublicKey;
/// Trait used to create a value from hex string for testing purposes.
pub(crate) trait TestFromHex {
/// Produces the value from hex.
///
/// ## Panics
///
/// The function panics if the hex or the value is invalid.
fn test_from_hex(hex: &str) -> Self;
}
impl<T: FromHex> TestFromHex for T {
fn test_from_hex(hex: &str) -> Self { Self::from_hex(hex).unwrap() }
}
impl TestFromHex for PublicKey {
fn test_from_hex(hex: &str) -> Self {
PublicKey::from_slice(&Vec::from_hex(hex).unwrap()).unwrap()
}
}
macro_rules! hex (($hex:literal) => (Vec::from_hex($hex).unwrap()));
pub(crate) use hex;
macro_rules! hex_into {
($hex:expr) => {
$crate::internal_macros::hex_into!(_, $hex)
};
($type:ty, $hex:expr) => {
<$type as $crate::internal_macros::TestFromHex>::test_from_hex($hex)
};
}
pub(crate) use hex_into;
// Script is commonly used in places where inference may fail
macro_rules! hex_script (($hex:expr) => ($crate::internal_macros::hex_into!($crate::Script, $hex)));
pub(crate) use hex_script; pub(crate) use hex_script;
macro_rules! hex_hash (($h:ident, $s:expr) => ($h::from_slice(&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()).unwrap())); // For types that can't use TestFromHex due to coherence rules or reversed hex
pub(crate) use hex_hash; macro_rules! hex_from_slice {
($hex:expr) => {
$crate::internal_macros::hex_from_slice!(_, $hex)
};
($type:ty, $hex:expr) => {
<$type>::from_slice(
&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($hex)
.unwrap(),
)
.unwrap()
};
}
pub(crate) use hex_from_slice;
macro_rules! hex_decode (($h:ident, $s:expr) => (deserialize::<$h>(&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()).unwrap())); macro_rules! hex_decode (($h:ident, $s:expr) => (deserialize::<$h>(&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()).unwrap()));
pub(crate) use hex_decode; pub(crate) use hex_decode;

View File

@ -263,6 +263,7 @@ impl PublicKey {
pub fn from_private_key<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &PrivateKey) -> PublicKey { pub fn from_private_key<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &PrivateKey) -> PublicKey {
sk.public_key(secp) sk.public_key(secp)
} }
} }
/// An opaque return type for PublicKey::to_sort_key /// An opaque return type for PublicKey::to_sort_key

View File

@ -1104,7 +1104,7 @@ mod tests {
use crate::hashes::hex::{FromHex, ToHex}; use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::{Hash, HashEngine}; use crate::hashes::{Hash, HashEngine};
use crate::hash_types::Sighash; use crate::hash_types::Sighash;
use crate::internal_macros::{hex_hash, hex_script, hex_decode}; use crate::internal_macros::{hex_into, hex_script, hex_decode, hex_from_slice};
use crate::network::constants::Network; use crate::network::constants::Network;
use crate::util::key::PublicKey; use crate::util::key::PublicKey;
use crate::util::sighash::{Annex, Error, Prevouts, ScriptPath, SighashCache}; use crate::util::sighash::{Annex, Error, Prevouts, ScriptPath, SighashCache};
@ -1447,19 +1447,19 @@ mod tests {
for inp in key_path["inputSpending"].as_array().unwrap() { for inp in key_path["inputSpending"].as_array().unwrap() {
let tx_ind = inp["given"]["txinIndex"].as_u64().unwrap() as usize; let tx_ind = inp["given"]["txinIndex"].as_u64().unwrap() as usize;
let internal_priv_key = hex_hash!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap()); let internal_priv_key = hex_from_slice!(SecretKey, inp["given"]["internalPrivkey"].as_str().unwrap());
let merkle_root = if inp["given"]["merkleRoot"].is_null() { let merkle_root = if inp["given"]["merkleRoot"].is_null() {
None None
} else { } else {
Some(hex_hash!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap())) Some(hex_into!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap()))
}; };
let hash_ty = SchnorrSighashType::from_consensus_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap(); let hash_ty = SchnorrSighashType::from_consensus_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap();
let expected_internal_pk = hex_hash!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap()); let expected_internal_pk = hex_from_slice!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap());
let expected_tweak = hex_hash!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap()); let expected_tweak = hex_into!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap());
let expected_tweaked_priv_key = hex_hash!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap()); let expected_tweaked_priv_key = hex_from_slice!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap(); let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
let expected_sighash = hex_hash!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap()); let expected_sighash = hex_into!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
let sig_str = inp["expected"]["witness"][0].as_str().unwrap(); let sig_str = inp["expected"]["witness"][0].as_str().unwrap();
let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 { let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 {
(secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default) (secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default)
@ -1566,18 +1566,18 @@ mod tests {
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_hash!(Sighash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") hex_from_slice!(Sighash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_hash!( assert_eq!(cache.prevouts, hex_from_slice!(
Hash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37" "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
)); ));
assert_eq!(cache.sequences, hex_hash!( assert_eq!(cache.sequences, hex_from_slice!(
Hash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b" "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
)); ));
assert_eq!(cache.outputs, hex_hash!( assert_eq!(cache.outputs, hex_from_slice!(
Hash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5" "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
)); ));
} }
@ -1597,18 +1597,18 @@ mod tests {
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_hash!(Sighash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") hex_from_slice!(Sighash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_hash!( assert_eq!(cache.prevouts, hex_from_slice!(
Hash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a" "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
)); ));
assert_eq!(cache.sequences, hex_hash!( assert_eq!(cache.sequences, hex_from_slice!(
Hash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198" "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
)); ));
assert_eq!(cache.outputs, hex_hash!( assert_eq!(cache.outputs, hex_from_slice!(
Hash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83" "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
)); ));
} }
@ -1634,18 +1634,18 @@ mod tests {
let mut cache = SighashCache::new(&tx); let mut cache = SighashCache::new(&tx);
assert_eq!( assert_eq!(
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(), cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
hex_hash!(Sighash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") hex_from_slice!(Sighash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
); );
let cache = cache.segwit_cache(); let cache = cache.segwit_cache();
assert_eq!(cache.prevouts, hex_hash!( assert_eq!(cache.prevouts, hex_from_slice!(
Hash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
)); ));
assert_eq!(cache.sequences, hex_hash!( assert_eq!(cache.sequences, hex_from_slice!(
Hash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044" "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
)); ));
assert_eq!(cache.outputs, hex_hash!( assert_eq!(cache.outputs, hex_from_slice!(
Hash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc" "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
)); ));
} }
} }