use bitcoin::address::NetworkUnchecked;
use bitcoin::Address;
use sha2::{Digest, Sha256};
use crate::error::{ElectrumError, Result};
pub fn address_to_scripthash(address: &str) -> Result<String> {
let addr: Address<NetworkUnchecked> = address
.parse()
.map_err(|e| ElectrumError::InvalidAddress(format!("{}: {}", address, e)))?;
let script = addr.assume_checked().script_pubkey();
let hash = Sha256::digest(script.as_bytes());
let reversed: Vec<u8> = hash.iter().rev().cloned().collect();
Ok(hex::encode(reversed))
}
pub fn addresses_to_scripthashes(addresses: &[&str]) -> Result<Vec<String>> {
addresses.iter().map(|a| address_to_scripthash(a)).collect()
}
pub fn is_valid_scripthash(scripthash: &str) -> bool {
scripthash.len() == 64 && scripthash.chars().all(|c| c.is_ascii_hexdigit())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_p2pkh_address() {
let scripthash =
address_to_scripthash("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap();
assert_eq!(scripthash.len(), 64);
assert_eq!(
scripthash,
"8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161"
);
}
#[test]
fn test_p2sh_address() {
let scripthash =
address_to_scripthash("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy").unwrap();
assert_eq!(scripthash.len(), 64);
}
#[test]
fn test_p2wpkh_address() {
let scripthash =
address_to_scripthash("bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq").unwrap();
assert_eq!(scripthash.len(), 64);
}
#[test]
fn test_p2tr_address() {
let scripthash = address_to_scripthash(
"bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297",
)
.unwrap();
assert_eq!(scripthash.len(), 64);
}
#[test]
fn test_invalid_address() {
let result = address_to_scripthash("invalid_address");
assert!(result.is_err());
}
#[test]
fn test_batch_conversion() {
let addresses = vec![
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy",
];
let scripthashes = addresses_to_scripthashes(&addresses).unwrap();
assert_eq!(scripthashes.len(), 2);
}
#[test]
fn test_valid_scripthash() {
assert!(is_valid_scripthash(
"8b01df4e368ea28f8dc0423bcf7a4923e3a12d307c875e47a0cfbf90b5c39161"
));
assert!(!is_valid_scripthash("invalid"));
assert!(!is_valid_scripthash("8b01df4e368ea28f8dc0423bcf7a4923")); }
}