Files
brk/_src/structs/address.rs
2025-02-23 01:25:15 +01:00

118 lines
3.9 KiB
Rust

use bitcoin_hashes::hash160;
use brk_parser::bitcoin::TxOut;
use super::{AddressType, Counter, U8x19, U8x31};
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
pub enum Address {
// https://mempool.space/tx/7bd54def72825008b4ca0f4aeff13e6be2c5fe0f23430629a9d484a1ac2a29b8
Empty(u32),
OpReturn(u32),
PushOnly(u32),
Unknown(u32),
// https://mempool.space/tx/274f8be3b7b9b1a220285f5f71f61e2691dd04df9d69bb02a8b3b85f91fb1857
MultiSig(u32),
P2PK((u16, U8x19)),
P2PKH((u16, U8x19)),
P2SH((u16, U8x19)),
P2WPKH((u16, U8x19)),
P2WSH((u16, U8x31)),
P2TR((u16, U8x31)),
}
impl Address {
pub fn to_type(&self) -> AddressType {
match self {
Self::Empty(_) => AddressType::Empty,
Self::OpReturn(_) => AddressType::OpReturn,
Self::PushOnly(_) => AddressType::PushOnly,
Self::Unknown(_) => AddressType::Unknown,
Self::MultiSig(_) => AddressType::MultiSig,
Self::P2PK(_) => AddressType::P2PK,
Self::P2PKH(_) => AddressType::P2PKH,
Self::P2SH(_) => AddressType::P2SH,
Self::P2WPKH(_) => AddressType::P2WPKH,
Self::P2WSH(_) => AddressType::P2WSH,
Self::P2TR(_) => AddressType::P2TR,
}
}
pub fn from(
txout: &TxOut,
multisig_addresses: &mut Counter,
op_return_addresses: &mut Counter,
push_only_addresses: &mut Counter,
unknown_addresses: &mut Counter,
empty_addresses: &mut Counter,
) -> Self {
let script = &txout.script_pubkey;
if script.is_p2pk() {
let pk = match script.as_bytes().len() {
67 => &script.as_bytes()[1..66],
35 => &script.as_bytes()[1..34],
_ => unreachable!(),
};
let hash = hash160::Hash::hash(pk);
let (prefix, rest) = Self::split_slice(&hash.as_byte_array()[..]);
Self::P2PK((prefix, rest.into()))
} else if script.is_p2pkh() {
let (prefix, rest) = Self::split_slice(&script.as_bytes()[3..23]);
Self::P2PKH((prefix, rest.into()))
} else if script.is_p2sh() {
let (prefix, rest) = Self::split_slice(&script.as_bytes()[2..22]);
Self::P2SH((prefix, rest.into()))
} else if script.is_p2wpkh() {
let (prefix, rest) = Self::split_slice(&script.as_bytes()[2..]);
Self::P2WPKH((prefix, rest.into()))
} else if script.is_p2wsh() {
let (prefix, rest) = Self::split_slice(&script.as_bytes()[2..]);
Self::P2WSH((prefix, rest.into()))
} else if script.is_p2tr() {
let (prefix, rest) = Self::split_slice(&script.as_bytes()[2..]);
Self::P2TR((prefix, rest.into()))
} else if script.is_empty() {
let index = empty_addresses.inner();
empty_addresses.increment();
Self::Empty(index)
} else if script.is_op_return() {
let index = op_return_addresses.inner();
op_return_addresses.increment();
Self::OpReturn(index)
} else if script.is_multisig() {
let index = multisig_addresses.inner();
multisig_addresses.increment();
Self::MultiSig(index)
} else if script.is_push_only() {
let index = push_only_addresses.inner();
push_only_addresses.increment();
Self::PushOnly(index)
} else {
Self::new_unknown(unknown_addresses)
}
}
fn new_unknown(unknown_addresses: &mut Counter) -> Address {
let index = unknown_addresses.inner();
unknown_addresses.increment();
Self::Unknown(index)
}
fn split_slice(slice: &[u8]) -> (u16, &[u8]) {
let prefix = ((slice[0] as u16) << 2) + ((slice[1] as u16) >> 6);
let rest = &slice[1..];
(prefix, rest)
}
}