use std::fmt::Debug;
use std::str::FromStr;
use hex::FromHexError;
use itertools::Itertools;
use crate::utils::sha256::IntoHash256;
#[derive(Hash, PartialEq, PartialOrd, Eq, Ord, bytemuck::Pod, bytemuck::Zeroable, Copy, Clone, Default)]
#[repr(C, align(8))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Hash256(pub [u8; 32]);
#[derive(Debug, thiserror::Error)]
pub enum HashError {
#[error(":{0}")]
FromHex(#[from] FromHexError),
#[error("Wrong vec len (should be 32)")]
VecWrongLength,
}
impl Hash256 {
pub const EMPTY: Self = Hash256([
227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
]);
pub fn chain_hash(self, add: &impl IntoHash256) -> Self {
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&self.0);
bytes[32..].copy_from_slice(&add.hash_256().0);
bytes.as_slice().hash_256()
}
}
impl From<Hash256> for primitive_types::H256 {
fn from(value: Hash256) -> Self {
value.0.into()
}
}
impl Debug for Hash256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Sha256").field(&self.to_string()).finish()
}
}
impl From<Hash256> for [u8; 32] {
fn from(value: Hash256) -> Self {
value.0
}
}
impl From<[u8; 32]> for Hash256 {
fn from(val: [u8; 32]) -> Self {
Hash256(val)
}
}
impl From<primitive_types::H256> for Hash256 {
fn from(val: primitive_types::H256) -> Self {
Hash256(val.0)
}
}
impl TryFrom<&'_ [u8]> for Hash256 {
type Error = HashError;
fn try_from(v: &'_ [u8]) -> Result<Self, Self::Error> {
let sha256 = v.try_into().map_err(|_| HashError::VecWrongLength)?;
Ok(Self(sha256))
}
}
impl std::fmt::Display for Hash256 {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", hex::encode(self.0))
}
}
impl FromStr for Hash256 {
type Err = HashError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let sha256 = hex::decode(s)?.into_iter().collect_vec();
let sha256: [u8; 32] = sha256.try_into().map_err(|_| HashError::VecWrongLength)?;
Ok(Hash256(sha256))
}
}
impl<'de> serde::Deserialize<'de> for Hash256 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = <String>::deserialize(deserializer)?;
Hash256::from_str(&v).map_err(serde::de::Error::custom)
}
}
impl serde::Serialize for Hash256 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(self)
}
}
#[cfg(feature = "schema")]
impl schemars::JsonSchema for Hash256 {
fn schema_name() -> std::borrow::Cow<'static, str> {
"Outpoint".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"type": "string",
"pattern": "^[0-9a-fA-F]{64}$",
"description": "SHA-256 transaction hexadecimal hash"
})
}
}