use crate::byron::{ByronAddress, ByronAddressError};
use crate::genesis::network_info::NetworkInfo;
use bech32::ToBase32;
use cbor_event::{de::Deserializer, se::Serializer};
use derivative::Derivative;
use schemars::JsonSchema;
use std::convert::{TryFrom, TryInto};
use std::io::{BufRead, Write};
use wasm_bindgen::prelude::wasm_bindgen;
use cml_crypto::{Ed25519KeyHash, ScriptHash};
use crate::certs::StakeCredential;
use cml_core::{
    error::{DeserializeError, DeserializeFailure},
    serialization::{Deserialize, LenEncoding, Serialize, StringEncoding},
    CertificateIndex, Slot, TransactionIndex,
};
fn variable_nat_decode(bytes: &[u8]) -> Option<(num_bigint::BigUint, usize)> {
    let mut output = num_bigint::BigUint::from(0u64);
    let mut bytes_read = 0;
    for byte in bytes {
        output = (output * 128u8) + (byte & 0x7F);
        bytes_read += 1;
        if (byte & 0x80) == 0 {
            return Some((output, bytes_read));
        }
    }
    None
}
fn variable_nat_encode(mut num: num_bigint::BigUint) -> Vec<u8> {
    use num_integer::Integer;
    let zero = num_bigint::BigUint::from(0u64);
    let divider = num_bigint::BigUint::from(128u64);
    let (next, chunk) = num.div_rem(÷r);
    let chunk_byte: u8 = chunk.try_into().unwrap();
    let mut output = vec![chunk_byte];
    num = next;
    while num > zero {
        let (next, chunk) = num.div_rem(÷r);
        let chunk_byte: u8 = chunk.try_into().unwrap();
        num = next;
        output.push(chunk_byte | 0x80);
    }
    output.reverse();
    output
}
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum AddressKind {
    Base,
    Ptr,
    Enterprise,
    Reward,
    Byron,
}
#[derive(Debug, thiserror::Error)]
pub enum AddressError {
    #[error("Bech32: {0}")]
    Bech32(#[from] bech32::Error),
    #[error("ByronError: {0}")]
    Byron(#[from] ByronAddressError),
    #[error("CBOR: {0}")]
    CBOR(#[from] DeserializeError),
    #[error("WrongKind: {:?}", 0)]
    WrongKind(AddressKind),
}
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum Address {
    Base(BaseAddress),
    Ptr(PointerAddress),
    Enterprise(EnterpriseAddress),
    Reward(RewardAddress),
    Byron(ByronAddress),
}
impl serde::Serialize for Address {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let bech32 = self
            .to_bech32(None)
            .map_err(|e| serde::ser::Error::custom(format!("to_bech32: {e:?}")))?;
        serializer.serialize_str(&bech32)
    }
}
impl<'de> serde::de::Deserialize<'de> for Address {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let bech32 = <String as serde::de::Deserialize>::deserialize(deserializer)?;
        Address::from_bech32(&bech32).map_err(|_e| {
            serde::de::Error::invalid_value(
                serde::de::Unexpected::Str(&bech32),
                &"bech32 address string",
            )
        })
    }
}
impl JsonSchema for Address {
    fn schema_name() -> String {
        String::from("Address")
    }
    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
        String::json_schema(gen)
    }
    fn is_referenceable() -> bool {
        String::is_referenceable()
    }
}
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum AddressHeaderKind {
    BasePaymentKeyStakeKey = 0b0000,
    BasePaymentScriptStakeKey = 0b0001,
    BasePaymentKeyStakeScript = 0b0010,
    BasePaymentScriptStakeScript = 0b0011,
    PointerKey = 0b0100,
    PointerScript = 0b0101,
    EnterpriseKey = 0b0110,
    EnterpriseScript = 0b0111,
    Byron = 0b1000,
    RewardKey = 0b1110,
    RewardScript = 0b1111,
}
impl Address {
    pub fn header(&self) -> u8 {
        fn stake_cred_bit(cred: &StakeCredential) -> u8 {
            match cred {
                StakeCredential::PubKey { .. } => 0,
                StakeCredential::Script { .. } => 1,
            }
        }
        match self {
            Self::Base(base) => {
                (stake_cred_bit(&base.payment) << 4)
                    | (stake_cred_bit(&base.stake) << 5)
                    | (base.network & 0xF)
            }
            Self::Ptr(ptr) => {
                0b0100_0000 | (stake_cred_bit(&ptr.payment) << 4) | (ptr.network & 0xF)
            }
            Self::Enterprise(enterprise) => {
                0b0110_0000
                    | (stake_cred_bit(&enterprise.payment) << 4)
                    | (enterprise.network & 0xF)
            }
            Self::Byron(_) => 0b1000 << 4, Self::Reward(reward) => {
                0b1110_0000 | (stake_cred_bit(&reward.payment) << 4) | (reward.network & 0xF)
            }
        }
    }
    pub fn header_matches_kind(header: u8, kind: AddressHeaderKind) -> bool {
        (header >> 4) == kind as u8
    }
    pub fn to_hex(&self) -> String {
        hex::encode(self.to_raw_bytes())
    }
    pub fn from_hex(hex: &str) -> Result<Address, DeserializeError> {
        hex::decode(hex)
            .map_err(|e| DeserializeFailure::InvalidStructure(Box::new(e)).into())
            .and_then(|bytes| Self::from_raw_bytes(&bytes))
    }
    pub fn to_raw_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::new();
        match self {
            Self::Base(base) => {
                buf.push(self.header());
                buf.extend(base.payment.to_raw_bytes());
                buf.extend(base.stake.to_raw_bytes());
            }
            Self::Ptr(ptr) => {
                buf.push(self.header());
                buf.extend(ptr.payment.to_raw_bytes());
                buf.extend(variable_nat_encode(ptr.stake.slot.clone()));
                buf.extend(variable_nat_encode(ptr.stake.tx_index.clone()));
                buf.extend(variable_nat_encode(ptr.stake.cert_index.clone()));
            }
            Self::Enterprise(enterprise) => {
                buf.push(self.header());
                buf.extend(enterprise.payment.to_raw_bytes());
            }
            Self::Reward(reward) => {
                buf.push(self.header());
                buf.extend(reward.payment.to_raw_bytes());
            }
            Self::Byron(byron) => {
                use cml_core::serialization::ToBytes;
                buf.extend(byron.to_bytes())
            }
        }
        if let Some(Some(trailing_bytes)) = self.encoding().map(|enc| &enc.trailing) {
            buf.extend(trailing_bytes.iter());
        }
        buf
    }
    pub fn from_raw_bytes(data: &[u8]) -> Result<Address, DeserializeError> {
        Self::from_bytes_impl(data, None)
    }
    pub(crate) fn from_bytes_impl(
        data: &[u8],
        bytes_encoding: Option<StringEncoding>,
    ) -> Result<Address, DeserializeError> {
        const TRAILING_WHITELIST: [&[u8]; 8] = [
            &[
                203, 87, 175, 176, 179, 95, 200, 156, 99, 6, 28, 153, 20, 224, 85, 0, 26, 81, 140,
                117, 22,
            ],
            &[
                19, 213, 244, 163, 254, 4, 120, 178, 36, 30, 1, 104, 227, 203, 165, 0, 26, 34, 193,
                90, 17,
            ],
            &[0],
            &[
                106, 51, 48, 102, 53, 97, 109, 107, 119, 104, 119, 113, 97, 52, 119, 118, 102, 121,
                106, 100, 101, 122, 121, 97, 101, 108, 109, 110, 110, 103, 100, 54, 100, 52, 101,
            ],
            &[
                53, 97, 99, 121, 50, 114, 48, 101, 107, 114, 112, 113, 122, 113, 106, 108, 113,
                100, 107, 56, 108, 122, 113, 110, 53, 114, 52, 53, 110,
            ],
            &[
                6, 29, 7, 12, 13, 4, 27, 7, 2, 15, 11, 13, 11, 15, 2, 9, 18, 5, 29, 28, 16, 9, 17,
                4, 14, 31, 7, 19, 17, 3, 1, 0, 11, 16, 22, 0,
            ],
            &[
                18, 110, 119, 53, 51, 53, 103, 54, 118, 115, 112, 55, 120, 55, 102, 104, 120, 112,
                113, 50, 112, 116, 115, 104, 57, 103, 107, 114,
            ],
            &[44],
        ];
        (|| -> Result<Self, DeserializeError> {
            let header = data[0];
            let network = header & 0x0F;
            const HASH_LEN: usize = Ed25519KeyHash::BYTE_COUNT;
            assert_eq!(ScriptHash::BYTE_COUNT, HASH_LEN);
            let read_addr_cred = |bit: u8, pos: usize| {
                let hash_bytes: [u8; HASH_LEN] = data[pos..pos + HASH_LEN].try_into().unwrap();
                if header & (1 << bit) == 0 {
                    StakeCredential::new_pub_key(Ed25519KeyHash::from(hash_bytes))
                } else {
                    StakeCredential::new_script(ScriptHash::from(hash_bytes))
                }
            };
            fn make_encoding(
                bytes_encoding: Option<StringEncoding>,
                trailing: Option<Vec<u8>>,
            ) -> Result<Option<AddressEncoding>, DeserializeError> {
                if trailing.is_some() || bytes_encoding.is_some() {
                    if let Some(trailing) = &trailing {
                        let mut found = false;
                        for ending in TRAILING_WHITELIST.iter() {
                            if trailing.as_slice() == *ending {
                                found = true;
                            }
                        }
                        if !found {
                            return Err(cbor_event::Error::TrailingData.into());
                        }
                    }
                    Ok(Some(AddressEncoding {
                        trailing,
                        bytes_encoding: bytes_encoding.unwrap_or_default(),
                    }))
                } else {
                    Ok(None)
                }
            }
            fn len_check_trailing(
                data: &[u8],
                addr_size: usize,
            ) -> Result<Option<Vec<u8>>, DeserializeFailure> {
                match data.len().cmp(&addr_size) {
                    std::cmp::Ordering::Less => Err(DeserializeFailure::CBOR(
                        cbor_event::Error::NotEnough(data.len(), addr_size),
                    )),
                    std::cmp::Ordering::Greater => Ok(Some(data[addr_size..].to_vec())),
                    std::cmp::Ordering::Equal => Ok(None),
                }
            }
            match (header & 0xF0) >> 4 {
                #[allow(clippy::manual_range_patterns)]
                0b0000 | 0b0001 | 0b0010 | 0b0011 => {
                    const BASE_ADDR_SIZE: usize = 1 + HASH_LEN * 2;
                    let trailing = len_check_trailing(data, BASE_ADDR_SIZE)?;
                    Ok(Address::Base(BaseAddress {
                        network,
                        payment: read_addr_cred(4, 1),
                        stake: read_addr_cred(5, 1 + HASH_LEN),
                        encoding: make_encoding(bytes_encoding, trailing)?,
                    }))
                }
                0b0100 | 0b0101 => {
                    const PTR_ADDR_MIN_SIZE: usize = 1 + HASH_LEN + 1 + 1 + 1;
                    if data.len() < PTR_ADDR_MIN_SIZE {
                        return Err(
                            cbor_event::Error::NotEnough(data.len(), PTR_ADDR_MIN_SIZE).into()
                        );
                    }
                    let mut byte_index = 1;
                    let payment_cred = read_addr_cred(4, 1);
                    byte_index += HASH_LEN;
                    let (slot, slot_bytes) =
                        variable_nat_decode(&data[byte_index..]).ok_or_else(|| {
                            DeserializeError::new(
                                "Address.Pointer.slot",
                                DeserializeFailure::VariableLenNatDecodeFailed,
                            )
                        })?;
                    byte_index += slot_bytes;
                    let (tx_index, tx_bytes) = variable_nat_decode(&data[byte_index..])
                        .ok_or_else(|| {
                            DeserializeError::new(
                                "Address.Pointer.tx_index",
                                DeserializeFailure::VariableLenNatDecodeFailed,
                            )
                        })?;
                    byte_index += tx_bytes;
                    let (cert_index, cert_bytes) = variable_nat_decode(&data[byte_index..])
                        .ok_or_else(|| {
                            DeserializeError::new(
                                "Address.Pointer.cert_index",
                                DeserializeFailure::VariableLenNatDecodeFailed,
                            )
                        })?;
                    byte_index += cert_bytes;
                    let trailing = if byte_index < data.len() {
                        Some(data[byte_index..].to_vec())
                    } else {
                        None
                    };
                    Ok(Address::Ptr(PointerAddress {
                        network,
                        payment: payment_cred,
                        stake: Pointer {
                            slot,
                            tx_index,
                            cert_index,
                        },
                        encoding: make_encoding(bytes_encoding, trailing)?,
                    }))
                }
                0b0110 | 0b0111 => {
                    const ENTERPRISE_ADDR_SIZE: usize = 1 + HASH_LEN;
                    let trailing = len_check_trailing(data, ENTERPRISE_ADDR_SIZE)?;
                    Ok(Address::Enterprise(EnterpriseAddress {
                        network,
                        payment: read_addr_cred(4, 1),
                        encoding: make_encoding(bytes_encoding, trailing)?,
                    }))
                }
                0b1110 | 0b1111 => {
                    const REWARD_ADDR_SIZE: usize = 1 + HASH_LEN;
                    let trailing = len_check_trailing(data, REWARD_ADDR_SIZE)?;
                    Ok(Address::Reward(RewardAddress {
                        network,
                        payment: read_addr_cred(4, 1),
                        encoding: make_encoding(bytes_encoding, trailing)?,
                    }))
                }
                0b1000 => {
                    ByronAddress::from_cbor_bytes(data)
                        .map(Address::Byron)
                        .map_err(|e| DeserializeFailure::InvalidStructure(Box::new(e)).into())
                }
                _ => Err(DeserializeFailure::BadAddressType(header).into()),
            }
        })()
        .map_err(|e| e.annotate("Address"))
    }
    pub fn to_bech32(&self, prefix: Option<String>) -> Result<String, AddressError> {
        let final_prefix = match prefix {
            Some(prefix) => prefix,
            None => {
                let prefix_header = match self {
                    Self::Reward(_) => "stake",
                    _ => "addr",
                };
                let prefix_tail = match self.network_id()? {
                    id if id == NetworkInfo::testnet().network_id() => "_test",
                    _ => "",
                };
                format!("{prefix_header}{prefix_tail}")
            }
        };
        bech32::encode(&final_prefix, self.to_raw_bytes().to_base32()).map_err(|e| e.into())
    }
    pub fn from_bech32(bech_str: &str) -> Result<Address, AddressError> {
        let (_hrp, u5data) = bech32::decode(bech_str)?;
        let data: Vec<u8> = bech32::FromBase32::from_base32(&u5data).unwrap();
        Ok(Self::from_bytes_impl(data.as_ref(), None)?)
    }
    pub fn is_valid_bech32(bech_str: &str) -> bool {
        match Self::from_bech32(bech_str) {
            Ok(_v) => true,
            Err(_err) => false,
        }
    }
    pub fn is_valid_byron(base58: &str) -> bool {
        ByronAddress::is_valid(base58)
    }
    pub fn is_valid(bech_str: &str) -> bool {
        Self::is_valid_bech32(bech_str) || Self::is_valid_byron(bech_str)
    }
    pub fn kind(&self) -> AddressKind {
        match self {
            Self::Base(_) => AddressKind::Base,
            Self::Byron(_) => AddressKind::Byron,
            Self::Enterprise(_) => AddressKind::Enterprise,
            Self::Ptr(_) => AddressKind::Ptr,
            Self::Reward(_) => AddressKind::Reward,
        }
    }
    pub fn network_id(&self) -> Result<u8, AddressError> {
        match self {
            Self::Base(a) => Ok(a.network),
            Self::Enterprise(a) => Ok(a.network),
            Self::Ptr(a) => Ok(a.network),
            Self::Reward(a) => Ok(a.network),
            Self::Byron(a) => a.content.network_id().map_err(Into::into),
        }
    }
    pub fn payment_cred(&self) -> Option<&StakeCredential> {
        match self {
            Self::Base(a) => Some(&a.payment),
            Self::Enterprise(a) => Some(&a.payment),
            Self::Ptr(a) => Some(&a.payment),
            Self::Reward(a) => Some(&a.payment),
            Self::Byron(_) => None,
        }
    }
    pub fn staking_cred(&self) -> Option<&StakeCredential> {
        match self {
            Self::Base(a) => Some(&a.stake),
            Self::Enterprise(_) => None,
            Self::Ptr(_) => None,
            Self::Reward(_) => None,
            Self::Byron(_) => None,
        }
    }
    pub(crate) fn encoding(&self) -> Option<&AddressEncoding> {
        match self {
            Self::Base(a) => a.encoding.as_ref(),
            Self::Enterprise(a) => a.encoding.as_ref(),
            Self::Ptr(a) => a.encoding.as_ref(),
            Self::Reward(a) => a.encoding.as_ref(),
            Self::Byron(_a) => None,
        }
    }
}
#[derive(Debug, Clone, Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct BaseAddress {
    pub network: u8,
    pub payment: StakeCredential,
    pub stake: StakeCredential,
    #[derivative(
        PartialEq = "ignore",
        Ord = "ignore",
        PartialOrd = "ignore",
        Hash = "ignore"
    )]
    pub(crate) encoding: Option<AddressEncoding>,
}
impl BaseAddress {
    pub fn new(network: u8, payment: StakeCredential, stake: StakeCredential) -> Self {
        Self {
            network,
            payment,
            stake,
            encoding: None,
        }
    }
    pub fn to_address(self) -> Address {
        self.into()
    }
    pub fn from_address(addr: &Address) -> Option<Self> {
        match addr {
            Address::Base(base) => Some(base.clone()),
            _ => None,
        }
    }
}
impl TryFrom<Address> for BaseAddress {
    type Error = AddressError;
    fn try_from(addr: Address) -> Result<Self, Self::Error> {
        match addr {
            Address::Base(base) => Ok(base),
            _ => Err(AddressError::WrongKind(addr.kind())),
        }
    }
}
impl From<BaseAddress> for Address {
    fn from(enterprise: BaseAddress) -> Self {
        Self::Base(enterprise)
    }
}
#[derive(Debug, Clone, Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EnterpriseAddress {
    pub network: u8,
    pub payment: StakeCredential,
    #[derivative(
        PartialEq = "ignore",
        Ord = "ignore",
        PartialOrd = "ignore",
        Hash = "ignore"
    )]
    pub(crate) encoding: Option<AddressEncoding>,
}
impl EnterpriseAddress {
    pub fn new(network: u8, payment: StakeCredential) -> Self {
        Self {
            network,
            payment,
            encoding: None,
        }
    }
    pub fn to_address(self) -> Address {
        self.into()
    }
    pub fn from_address(addr: &Address) -> Option<Self> {
        match addr {
            Address::Enterprise(enterprise) => Some(enterprise.clone()),
            _ => None,
        }
    }
}
impl TryFrom<Address> for EnterpriseAddress {
    type Error = AddressError;
    fn try_from(addr: Address) -> Result<Self, Self::Error> {
        match addr {
            Address::Enterprise(enterprise) => Ok(enterprise),
            _ => Err(AddressError::WrongKind(addr.kind())),
        }
    }
}
impl From<EnterpriseAddress> for Address {
    fn from(enterprise: EnterpriseAddress) -> Self {
        Self::Enterprise(enterprise)
    }
}
pub type RewardAccount = RewardAddress;
#[derive(Debug, Clone, Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RewardAddress {
    pub network: u8,
    pub payment: StakeCredential,
    #[derivative(
        PartialEq = "ignore",
        Ord = "ignore",
        PartialOrd = "ignore",
        Hash = "ignore"
    )]
    pub(crate) encoding: Option<AddressEncoding>,
}
impl RewardAddress {
    pub fn new(network: u8, payment: StakeCredential) -> Self {
        Self {
            network,
            payment,
            encoding: None,
        }
    }
    pub fn to_address(self) -> Address {
        self.into()
    }
    pub fn from_address(addr: &Address) -> Option<Self> {
        match addr {
            Address::Reward(reward) => Some(reward.clone()),
            _ => None,
        }
    }
}
impl TryFrom<Address> for RewardAddress {
    type Error = AddressError;
    fn try_from(addr: Address) -> Result<Self, Self::Error> {
        match addr {
            Address::Reward(reward) => Ok(reward),
            _ => Err(AddressError::WrongKind(addr.kind())),
        }
    }
}
impl From<RewardAddress> for Address {
    fn from(reward: RewardAddress) -> Self {
        Self::Reward(reward)
    }
}
impl serde::Serialize for RewardAddress {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let bech32 = self
            .clone()
            .to_address()
            .to_bech32(None)
            .map_err(|e| serde::ser::Error::custom(format!("to_bech32: {e:?}")))?;
        serializer.serialize_str(&bech32)
    }
}
impl<'de> serde::de::Deserialize<'de> for RewardAddress {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let bech32 = <String as serde::de::Deserialize>::deserialize(deserializer)?;
        match Address::from_bech32(&bech32)
            .ok()
            .map(|addr| RewardAddress::from_address(&addr))
        {
            Some(Some(ra)) => Ok(ra),
            _ => Err(serde::de::Error::invalid_value(
                serde::de::Unexpected::Str(&bech32),
                &"bech32 reward address string",
            )),
        }
    }
}
impl JsonSchema for RewardAddress {
    fn schema_name() -> String {
        String::from("RewardAddress")
    }
    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
        String::json_schema(gen)
    }
    fn is_referenceable() -> bool {
        String::is_referenceable()
    }
}
#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub struct Pointer {
    slot: num_bigint::BigUint,
    tx_index: num_bigint::BigUint,
    cert_index: num_bigint::BigUint,
}
impl Pointer {
    pub fn new(slot: Slot, tx_index: TransactionIndex, cert_index: CertificateIndex) -> Self {
        Self {
            slot: num_bigint::BigUint::from(slot),
            tx_index: num_bigint::BigUint::from(tx_index),
            cert_index: num_bigint::BigUint::from(cert_index),
        }
    }
    pub fn slot(&self) -> Slot {
        self.slot.clone().try_into().unwrap_or(u64::MAX)
    }
    pub fn tx_index(&self) -> Slot {
        self.tx_index.clone().try_into().unwrap_or(u64::MAX)
    }
    pub fn cert_index(&self) -> Slot {
        self.cert_index.clone().try_into().unwrap_or(u64::MAX)
    }
}
#[derive(Debug, Clone, Derivative)]
#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PointerAddress {
    pub network: u8,
    pub payment: StakeCredential,
    pub stake: Pointer,
    #[derivative(
        PartialEq = "ignore",
        Ord = "ignore",
        PartialOrd = "ignore",
        Hash = "ignore"
    )]
    pub(crate) encoding: Option<AddressEncoding>,
}
impl PointerAddress {
    pub fn new(network: u8, payment: StakeCredential, stake: Pointer) -> Self {
        Self {
            network,
            payment,
            stake,
            encoding: None,
        }
    }
    pub fn to_address(self) -> Address {
        self.into()
    }
    pub fn from_address(addr: &Address) -> Option<Self> {
        match addr {
            Address::Ptr(pointer) => Some(pointer.clone()),
            _ => None,
        }
    }
}
impl TryFrom<Address> for PointerAddress {
    type Error = AddressError;
    fn try_from(addr: Address) -> Result<Self, Self::Error> {
        match addr {
            Address::Ptr(pointer) => Ok(pointer),
            _ => Err(AddressError::WrongKind(addr.kind())),
        }
    }
}
impl From<PointerAddress> for Address {
    fn from(pointer: PointerAddress) -> Self {
        Self::Ptr(pointer)
    }
}
#[derive(Clone, Debug)]
pub struct AddressEncoding {
    pub(crate) trailing: Option<Vec<u8>>,
    pub(crate) bytes_encoding: StringEncoding,
}
#[derive(Clone, Debug, Default)]
pub struct StakeCredentialEncoding {
    pub len_encoding: LenEncoding,
    pub index_0_encoding: Option<cbor_event::Sz>,
}
impl Serialize for Address {
    fn serialize<'se, W: Write>(
        &self,
        serializer: &'se mut Serializer<W>,
        force_canonical: bool,
    ) -> cbor_event::Result<&'se mut Serializer<W>> {
        let raw_bytes = self.to_raw_bytes();
        serializer.write_bytes_sz(
            &raw_bytes,
            self.encoding()
                .map(|encs| encs.bytes_encoding.clone())
                .unwrap_or_default()
                .to_str_len_sz(raw_bytes.len() as u64, force_canonical),
        )
    }
}
impl Deserialize for Address {
    fn deserialize<R: BufRead>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
        let (raw_bytes, encoding) = raw.bytes_sz()?;
        Self::from_bytes_impl(raw_bytes.as_ref(), Some(encoding.into()))
    }
}
impl Serialize for RewardAccount {
    fn serialize<'se, W: Write>(
        &self,
        serializer: &'se mut Serializer<W>,
        force_canonical: bool,
    ) -> cbor_event::Result<&'se mut Serializer<W>> {
        Address::from(self.clone()).serialize(serializer, force_canonical)
    }
}
impl Deserialize for RewardAccount {
    fn deserialize<R: BufRead>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
        let (raw_bytes, encoding) = raw.bytes_sz()?;
        match Address::from_bytes_impl(raw_bytes.as_ref(), Some(encoding.into()))? {
            Address::Reward(reward_address) => Ok(reward_address),
            _ => Err(DeserializeFailure::BadAddressType(raw_bytes[0]).into()),
        }
    }
}
#[cfg(test)]
mod tests {
    use crate::{byron::AddressContent, transaction::NativeScript};
    use super::*;
    use cml_core::serialization::ToBytes;
    use cml_crypto::*;
    #[test]
    fn variable_nat_encoding() {
        let cases = [0u64, 127u64, 128u64, 255u64, 256275757658493284u64];
        for case in cases.iter() {
            let case_biguint = num_bigint::BigUint::from(*case);
            let encoded = variable_nat_encode(case_biguint.clone());
            let decoded = variable_nat_decode(&encoded).unwrap().0;
            assert_eq!(case_biguint, decoded);
        }
    }
    #[test]
    fn base_serialize_consistency() {
        let base = BaseAddress::new(
            5,
            StakeCredential::new_pub_key(Ed25519KeyHash::from([23; Ed25519KeyHash::BYTE_COUNT])),
            StakeCredential::new_script(ScriptHash::from([42; ScriptHash::BYTE_COUNT])),
        );
        let addr = base.to_address();
        let addr2 = Address::from_cbor_bytes(&addr.to_cbor_bytes()).unwrap();
        assert_eq!(addr.to_cbor_bytes(), addr2.to_cbor_bytes());
    }
    #[test]
    fn ptr_serialize_consistency() {
        let ptr = PointerAddress::new(
            25,
            StakeCredential::new_pub_key(Ed25519KeyHash::from([23; Ed25519KeyHash::BYTE_COUNT])),
            Pointer::new(2354556573, 127, 0),
        );
        let addr = ptr.to_address();
        let addr2 = Address::from_cbor_bytes(&addr.to_cbor_bytes()).unwrap();
        assert_eq!(addr.to_cbor_bytes(), addr2.to_cbor_bytes());
    }
    #[test]
    fn enterprise_serialize_consistency() {
        let enterprise = EnterpriseAddress::new(
            64,
            StakeCredential::new_pub_key(Ed25519KeyHash::from([23; Ed25519KeyHash::BYTE_COUNT])),
        );
        let addr = enterprise.to_address();
        let addr2 = Address::from_cbor_bytes(&addr.to_cbor_bytes()).unwrap();
        assert_eq!(addr.to_cbor_bytes(), addr2.to_cbor_bytes());
    }
    #[test]
    fn reward_serialize_consistency() {
        let reward = RewardAddress::new(
            9,
            StakeCredential::new_script(ScriptHash::from([127; Ed25519KeyHash::BYTE_COUNT])),
        );
        let addr = reward.to_address();
        let addr2 = Address::from_cbor_bytes(&addr.to_cbor_bytes()).unwrap();
        assert_eq!(addr.to_cbor_bytes(), addr2.to_cbor_bytes());
    }
    #[test]
    fn address_header_matching() {
        let reward = RewardAddress::new(
            0b1001,
            StakeCredential::new_script(ScriptHash::from([127; Ed25519KeyHash::BYTE_COUNT])),
        )
        .to_address();
        assert_eq!(reward.header(), 0b1111_1001);
        assert!(Address::header_matches_kind(
            reward.header(),
            AddressHeaderKind::RewardScript
        ))
    }
    fn root_key_12() -> Bip32PrivateKey {
        let entropy = [
            0xdf, 0x9e, 0xd2, 0x5e, 0xd1, 0x46, 0xbf, 0x43, 0x33, 0x6a, 0x5d, 0x7c, 0xf7, 0x39,
            0x59, 0x94,
        ];
        Bip32PrivateKey::from_bip39_entropy(&entropy, &[])
    }
    fn root_key_15() -> Bip32PrivateKey {
        let entropy = [
            0x0c, 0xcb, 0x74, 0xf3, 0x6b, 0x7d, 0xa1, 0x64, 0x9a, 0x81, 0x44, 0x67, 0x55, 0x22,
            0xd4, 0xd8, 0x09, 0x7c, 0x64, 0x12,
        ];
        Bip32PrivateKey::from_bip39_entropy(&entropy, &[])
    }
    fn root_key_24() -> Bip32PrivateKey {
        let entropy = [
            0x4e, 0x82, 0x8f, 0x9a, 0x67, 0xdd, 0xcf, 0xf0, 0xe6, 0x39, 0x1a, 0xd4, 0xf2, 0x6d,
            0xdb, 0x75, 0x79, 0xf5, 0x9b, 0xa1, 0x4b, 0x6d, 0xd4, 0xba, 0xf6, 0x3d, 0xcf, 0xdb,
            0x9d, 0x24, 0x20, 0xda,
        ];
        Bip32PrivateKey::from_bip39_entropy(&entropy, &[])
    }
    fn harden(index: u32) -> u32 {
        index | 0x80_00_00_00
    }
    #[test]
    fn bech32_parsing() {
        let addr =
            Address::from_bech32("addr1u8pcjgmx7962w6hey5hhsd502araxp26kdtgagakhaqtq8sxy9w7g")
                .unwrap();
        assert_eq!(
            addr.to_bech32(Some("foobar".to_string())).unwrap(),
            "foobar1u8pcjgmx7962w6hey5hhsd502araxp26kdtgagakhaqtq8s92n4tm"
        );
    }
    #[test]
    fn bip32_12_base() {
        let spend = root_key_12()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let stake = root_key_12()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(2)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let stake_cred = StakeCredential::new_pub_key(stake.to_raw_key().hash());
        let addr_net_0 = BaseAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            stake_cred.clone(),
        )
        .to_address();
        assert_eq!(addr_net_0.to_bech32(None).unwrap(), "addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwq2ytjqp");
        let addr_net_3 =
            BaseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred, stake_cred)
                .to_address();
        assert_eq!(addr_net_3.to_bech32(None).unwrap(), "addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwqfjkjv7");
    }
    #[test]
    fn bip32_12_enterprise() {
        let spend = root_key_12()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 =
            EnterpriseAddress::new(NetworkInfo::testnet().network_id(), spend_cred.clone())
                .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1vz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzerspjrlsz"
        );
        let addr_net_3 =
            EnterpriseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred).to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1vx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzers66hrl8"
        );
    }
    #[test]
    fn bip32_12_pointer() {
        let spend = root_key_12()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 = PointerAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            Pointer::new(1, 2, 3),
        )
        .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1gz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzerspqgpsqe70et"
        );
        let addr_net_3 = PointerAddress::new(
            NetworkInfo::mainnet().network_id(),
            spend_cred,
            Pointer::new(24157, 177, 42),
        )
        .to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1gx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer5ph3wczvf2w8lunk"
        );
    }
    #[test]
    fn bip32_15_base() {
        let spend = root_key_15()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let stake = root_key_15()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(2)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let stake_cred = StakeCredential::new_pub_key(stake.to_raw_key().hash());
        let addr_net_0 = BaseAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            stake_cred.clone(),
        )
        .to_address();
        assert_eq!(addr_net_0.to_bech32(None).unwrap(), "addr_test1qpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qum8x5w");
        let addr_net_3 =
            BaseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred, stake_cred)
                .to_address();
        assert_eq!(addr_net_3.to_bech32(None).unwrap(), "addr1q9u5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qld6xc3");
    }
    #[test]
    fn bip32_15_enterprise() {
        let spend = root_key_15()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 =
            EnterpriseAddress::new(NetworkInfo::testnet().network_id(), spend_cred.clone())
                .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1vpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5eg57c2qv"
        );
        let addr_net_3 =
            EnterpriseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred).to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1v9u5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5eg0kvk0f"
        );
    }
    #[test]
    fn bip32_15_pointer() {
        let spend = root_key_15()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 = PointerAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            Pointer::new(1, 2, 3),
        )
        .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1gpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5egpqgpsdhdyc0"
        );
        let addr_net_3 = PointerAddress::new(
            NetworkInfo::mainnet().network_id(),
            spend_cred,
            Pointer::new(24157, 177, 42),
        )
        .to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1g9u5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5evph3wczvf2kd5vam"
        );
    }
    #[test]
    fn bip32_15_byron() {
        let byron_key = root_key_15()
            .derive(harden(44))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let byron_addr =
            AddressContent::icarus_from_key(byron_key, NetworkInfo::mainnet().protocol_magic());
        assert_eq!(
            byron_addr.to_address().to_base58(),
            "Ae2tdPwUPEZHtBmjZBF4YpMkK9tMSPTE2ADEZTPN97saNkhG78TvXdp3GDk"
        );
        assert!(ByronAddress::is_valid(
            "Ae2tdPwUPEZHtBmjZBF4YpMkK9tMSPTE2ADEZTPN97saNkhG78TvXdp3GDk"
        ));
        assert_eq!(byron_addr.network_id().unwrap(), 0b0001);
        let generic_addr = Address::from_raw_bytes(&byron_addr.to_address().to_bytes()).unwrap();
        let byron_addr_2 = ByronAddress::from_address(&generic_addr).unwrap();
        assert_eq!(
            byron_addr.to_address().to_base58(),
            byron_addr_2.to_base58()
        );
    }
    #[test]
    fn bip32_24_base() {
        let spend = root_key_24()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let stake = root_key_24()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(2)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let stake_cred = StakeCredential::new_pub_key(stake.to_raw_key().hash());
        let addr_net_0 = BaseAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            stake_cred.clone(),
        )
        .to_address();
        assert_eq!(addr_net_0.to_bech32(None).unwrap(), "addr_test1qqy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmn8k8ttq8f3gag0h89aepvx3xf69g0l9pf80tqv7cve0l33sw96paj");
        let addr_net_3 =
            BaseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred, stake_cred)
                .to_address();
        assert_eq!(addr_net_3.to_bech32(None).unwrap(), "addr1qyy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmn8k8ttq8f3gag0h89aepvx3xf69g0l9pf80tqv7cve0l33sdn8p3d");
    }
    #[test]
    fn bip32_24_enterprise() {
        let spend = root_key_24()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 =
            EnterpriseAddress::new(NetworkInfo::testnet().network_id(), spend_cred.clone())
                .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1vqy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmnqtjtf68"
        );
        let addr_net_3 =
            EnterpriseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred).to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1vyy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmnqs6l44z"
        );
    }
    #[test]
    fn bip32_24_pointer() {
        let spend = root_key_24()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let addr_net_0 = PointerAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            Pointer::new(1, 2, 3),
        )
        .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "addr_test1gqy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmnqpqgps5mee0p"
        );
        let addr_net_3 = PointerAddress::new(
            NetworkInfo::mainnet().network_id(),
            spend_cred,
            Pointer::new(24157, 177, 42),
        )
        .to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "addr1gyy6nhfyks7wdu3dudslys37v252w2nwhv0fw2nfawemmnyph3wczvf2dqflgt"
        );
    }
    #[test]
    fn bip32_12_reward() {
        let staking_key = root_key_12()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(2)
            .derive(0)
            .to_public();
        let staking_cred = StakeCredential::new_pub_key(staking_key.to_raw_key().hash());
        let addr_net_0 =
            RewardAddress::new(NetworkInfo::testnet().network_id(), staking_cred.clone())
                .to_address();
        assert_eq!(
            addr_net_0.to_bech32(None).unwrap(),
            "stake_test1uqevw2xnsc0pvn9t9r9c7qryfqfeerchgrlm3ea2nefr9hqp8n5xl"
        );
        let addr_net_3 =
            RewardAddress::new(NetworkInfo::mainnet().network_id(), staking_cred).to_address();
        assert_eq!(
            addr_net_3.to_bech32(None).unwrap(),
            "stake1uyevw2xnsc0pvn9t9r9c7qryfqfeerchgrlm3ea2nefr9hqxdekzz"
        );
    }
    #[test]
    fn bip32_24_base_multisig_hd_derivation() {
        let spend = root_key_24()
            .derive(harden(1854))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let stake = root_key_24()
            .derive(harden(1854))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(2)
            .derive(0)
            .to_public();
        let spend_cred = StakeCredential::new_pub_key(spend.to_raw_key().hash());
        let stake_cred = StakeCredential::new_pub_key(stake.to_raw_key().hash());
        let addr_net_0 = BaseAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            stake_cred.clone(),
        )
        .to_address();
        assert_eq!(addr_net_0.to_bech32(None).unwrap(), "addr_test1qz8fg2e9yn0ga6sav0760cxmx0antql96mfuhqgzcc5swugw2jqqlugnx9qjep9xvcx40z0zfyep55r2t3lav5smyjrs96cusg");
        let addr_net_3 =
            BaseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred, stake_cred)
                .to_address();
        assert_eq!(addr_net_3.to_bech32(None).unwrap(), "addr1qx8fg2e9yn0ga6sav0760cxmx0antql96mfuhqgzcc5swugw2jqqlugnx9qjep9xvcx40z0zfyep55r2t3lav5smyjrsxv9uuh");
    }
    #[test]
    fn multisig_from_script() {
        let spend = root_key_24()
            .derive(harden(1852))
            .derive(harden(1815))
            .derive(harden(0))
            .derive(0)
            .derive(0)
            .to_public();
        let mut pubkey_native_scripts = Vec::new();
        let spending_hash = spend.to_raw_key().hash();
        pubkey_native_scripts.push(NativeScript::new_script_pubkey(spending_hash));
        let oneof_native_script = NativeScript::new_script_n_of_k(1, pubkey_native_scripts);
        let script_hash =
            ScriptHash::from_raw_bytes(oneof_native_script.hash().to_raw_bytes()).unwrap();
        let spend_cred = StakeCredential::new_script(script_hash);
        let stake_cred = StakeCredential::new_script(script_hash);
        let addr_net_0 = BaseAddress::new(
            NetworkInfo::testnet().network_id(),
            spend_cred.clone(),
            stake_cred.clone(),
        )
        .to_address();
        assert_eq!(addr_net_0.to_bech32(None).unwrap(), "addr_test1xr0de0mz3m9xmgtlmqqzu06s0uvfsczskdec8k7v4jhr7077mjlk9rk2dkshlkqq9cl4qlccnps9pvmns0duet9w8uls8flvxc");
        let addr_net_3 =
            BaseAddress::new(NetworkInfo::mainnet().network_id(), spend_cred, stake_cred)
                .to_address();
        assert_eq!(addr_net_3.to_bech32(None).unwrap(), "addr1x80de0mz3m9xmgtlmqqzu06s0uvfsczskdec8k7v4jhr7077mjlk9rk2dkshlkqq9cl4qlccnps9pvmns0duet9w8ulsylzv28");
    }
    #[test]
    fn pointer_address_big() {
        let addr = Address::from_bech32("addr_test1grqe6lg9ay8wkcu5k5e38lne63c80h3nq6xxhqfmhewf645pllllllllllll7lupllllllllllll7lupllllllllllll7lc9wayvj").unwrap();
        let ptr = PointerAddress::from_address(&addr).unwrap().stake;
        let u64_max = num_bigint::BigUint::from(u64::MAX);
        assert_eq!(u64_max, ptr.slot);
        assert_eq!(u64_max, ptr.tx_index);
        assert_eq!(u64_max, ptr.cert_index);
    }
    #[test]
    fn long_address() {
        let long = Address::from_bech32("addr1q9d66zzs27kppmx8qc8h43q7m4hkxp5d39377lvxefvxd8j7eukjsdqc5c97t2zg5guqadepqqx6rc9m7wtnxy6tajjvk4a0kze4ljyuvvrpexg5up2sqxj33363v35gtew").unwrap();
        let long_trimmed = Address::from_bech32("addr1q9d66zzs27kppmx8qc8h43q7m4hkxp5d39377lvxefvxd8j7eukjsdqc5c97t2zg5guqadepqqx6rc9m7wtnxy6tajjq6r54x9").unwrap();
        assert_eq!(long, long_trimmed);
        assert_eq!(
            long.encoding().unwrap().trailing,
            Some(vec![
                203u8, 87, 175, 176, 179, 95, 200, 156, 99, 6, 28, 153, 20, 224, 85, 0, 26, 81,
                140, 117, 22
            ])
        );
        assert_eq!(
            long_trimmed.encoding().and_then(|enc| enc.trailing.clone()),
            None
        );
        assert_eq!(
            hex::encode(long.to_raw_bytes()),
            "015bad085057ac10ecc7060f7ac41edd6f63068d8963ef7d86ca58669e5ecf2d283418a60be5a848a2380eb721000da1e0bbf39733134beca4cb57afb0b35fc89c63061c9914e055001a518c7516"
        );
        let long_not_whitelisted = Address::from_bech32(
            "addr_test1vqt3w9chzut3w9chzut3w9chzut3w9chzut3w9chzut3w9cqqspqvqcqsmxqdssg97",
        );
        assert!(long_not_whitelisted.is_err());
    }
    #[test]
    fn ptr_addr_huge_slot() {
        let addr_bytes: Vec<u8> = vec![
            64, 193, 157, 125, 5, 233, 14, 235, 99, 148, 181, 51, 19, 254, 121, 212, 112, 119, 222,
            51, 6, 140, 107, 129, 59, 190, 92, 157, 86, 129, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
            255, 255, 255, 255, 255, 255, 255, 255, 127, 129, 255, 255, 255, 255, 255, 255, 255,
            255, 127, 129, 255, 255, 255, 255, 255, 255, 255, 255, 127,
        ];
        let addr = Address::from_raw_bytes(&addr_bytes).unwrap();
        assert_eq!(addr_bytes, addr.to_raw_bytes());
    }
}