mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-04 22:33:06 +00:00
129 lines
3.1 KiB
Rust
129 lines
3.1 KiB
Rust
use std::{fmt::Display, str::FromStr};
|
|
|
|
use nssa_core::account::FingerPrint;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::signature::PublicKey;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
|
pub struct Address {
|
|
value: [u8; 32],
|
|
}
|
|
|
|
impl Address {
|
|
pub fn new(value: [u8; 32]) -> Self {
|
|
Self { value }
|
|
}
|
|
|
|
pub fn value(&self) -> &[u8; 32] {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for Address {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
impl From<&PublicKey> for Address {
|
|
fn from(value: &PublicKey) -> Self {
|
|
// TODO: Check specs
|
|
Self::new(*value.value())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum AddressError {
|
|
#[error("invalid hex")]
|
|
InvalidHex(#[from] hex::FromHexError),
|
|
#[error("invalid length: expected 32 bytes, got {0}")]
|
|
InvalidLength(usize),
|
|
}
|
|
|
|
impl FromStr for Address {
|
|
type Err = AddressError;
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let bytes = hex::decode(s)?;
|
|
if bytes.len() != 32 {
|
|
return Err(AddressError::InvalidLength(bytes.len()));
|
|
}
|
|
let mut value = [0u8; 32];
|
|
value.copy_from_slice(&bytes);
|
|
Ok(Address { value })
|
|
}
|
|
}
|
|
|
|
impl Display for Address {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", hex::encode(self.value))
|
|
}
|
|
}
|
|
|
|
impl Serialize for Address {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
let hex_string = self.to_string();
|
|
|
|
hex_string.serialize(serializer)
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Address {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
let hex_string = String::deserialize(deserializer)?;
|
|
|
|
Address::from_str(&hex_string).map_err(serde::de::Error::custom)
|
|
}
|
|
}
|
|
|
|
impl From<&Address> for FingerPrint {
|
|
fn from(address: &Address) -> Self {
|
|
FingerPrint::new(address.value)
|
|
}
|
|
}
|
|
|
|
impl From<Address> for FingerPrint {
|
|
fn from(address: Address) -> Self {
|
|
FingerPrint::new(address.value)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{Address, address::AddressError};
|
|
|
|
#[test]
|
|
fn parse_valid_address() {
|
|
let hex_str = "00".repeat(32); // 64 hex chars = 32 bytes
|
|
let addr: Address = hex_str.parse().unwrap();
|
|
assert_eq!(addr.value, [0u8; 32]);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_invalid_hex() {
|
|
let hex_str = "zz".repeat(32); // invalid hex chars
|
|
let result = hex_str.parse::<Address>().unwrap_err();
|
|
assert!(matches!(result, AddressError::InvalidHex(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_wrong_length_short() {
|
|
let hex_str = "00".repeat(31); // 62 chars = 31 bytes
|
|
let result = hex_str.parse::<Address>().unwrap_err();
|
|
assert!(matches!(result, AddressError::InvalidLength(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_wrong_length_long() {
|
|
let hex_str = "00".repeat(33); // 66 chars = 33 bytes
|
|
let result = hex_str.parse::<Address>().unwrap_err();
|
|
assert!(matches!(result, AddressError::InvalidLength(_)));
|
|
}
|
|
}
|